({
entry,
}: {
entry: TranscriptEntry & { feedType: 'tool_use' | 'tool_result' };
})
| 178 | } |
| 179 | |
| 180 | function ToolCard({ |
| 181 | entry, |
| 182 | }: { |
| 183 | entry: TranscriptEntry & { feedType: 'tool_use' | 'tool_result' }; |
| 184 | }) { |
| 185 | const diffFiles = ('diff' in entry ? entry.diff?.files : undefined) || []; |
| 186 | const status = entry.status || (entry.isError ? 'error' : 'success'); |
| 187 | const name = entry.toolName || entry.title || ''; |
| 188 | const isBash = isBashTool(name); |
| 189 | const isFile = isFileTool(name); |
| 190 | const hasDiff = diffFiles.length > 0; |
| 191 | const content = trimText(entry.content); |
| 192 | |
| 193 | if (entry.feedType === 'tool_use') { |
| 194 | return ( |
| 195 | <details className="group max-w-[88%]"> |
| 196 | <summary className="flex cursor-pointer list-none items-center gap-2 rounded-xl border border-[#E7DFD3] bg-[#F9F6F1] px-3 py-2 text-[13px] text-[#5C5247] transition-colors hover:bg-[#F4EEE4]"> |
| 197 | <span>{toolIcon(name)}</span> |
| 198 | <span className="font-medium">{toolLabel(name)}</span> |
| 199 | <ChevronRight className="ml-auto h-3.5 w-3.5 text-[#A99D8D] transition-transform group-open:rotate-90" /> |
| 200 | </summary> |
| 201 | {content ? ( |
| 202 | <div className="mt-1 ml-6 rounded-xl bg-[#FBF8F3] px-3 py-2 font-mono text-[11px] leading-5 text-[#6B6155]"> |
| 203 | {content.length > 300 ? `${content.slice(0, 300)}…` : content} |
| 204 | </div> |
| 205 | ) : null} |
| 206 | </details> |
| 207 | ); |
| 208 | } |
| 209 | |
| 210 | if (isBash && content) { |
| 211 | return ( |
| 212 | <details className="group max-w-[88%]" open> |
| 213 | <summary className="flex cursor-pointer list-none items-center gap-2 rounded-xl border border-[#E7DFD3] bg-[#F9F6F1] px-3 py-2 text-[13px] text-[#5C5247] transition-colors hover:bg-[#F4EEE4]"> |
| 214 | <span>🖥️</span> |
| 215 | <span className="font-medium">命令输出</span> |
| 216 | {status === 'error' ? ( |
| 217 | <span className="rounded-full border border-[#EBCFC6] bg-[#FFF1ED] px-2 py-0.5 text-[10px] text-[#A05545]">失败</span> |
| 218 | ) : null} |
| 219 | <ChevronRight className="ml-auto h-3.5 w-3.5 text-[#A99D8D] transition-transform group-open:rotate-90" /> |
| 220 | </summary> |
| 221 | <pre className={[ |
| 222 | 'mt-1 ml-6 overflow-x-auto rounded-xl p-3 font-mono text-[11px] leading-5', |
| 223 | status === 'error' |
| 224 | ? 'bg-[#2D1517] text-[#F07178]' |
| 225 | : 'bg-[#1E1E1E] text-[#D4D4D4]', |
| 226 | ].join(' ')}> |
| 227 | {content} |
| 228 | </pre> |
| 229 | </details> |
| 230 | ); |
| 231 | } |
| 232 | |
| 233 | if (hasDiff) { |
| 234 | return ( |
| 235 | <div className="max-w-[88%] space-y-1"> |
| 236 | {diffFiles.map(file => ( |
| 237 | <details key={file.filePath} className="group" open> |
nothing calls this directly
no test coverage detected