import { memo, useState } from "react"; import { Terminal, ChevronDown, ChevronRight, Loader2, } from "lucide-react"; import { cn } from "../lib/utils"; import type { ToolPart } from "../types/parts"; import { PreviewCard, PreviewError, PreviewLoading } from "./preview-primitives"; export interface CommandPreviewProps { part: ToolPart; } /** Extract stdout/stderr/exitCode from tool output. */ function extractCommandOutput(output: unknown): { stdout: string; stderr: string; exitCode: number; } { if (!output) return { stdout: "", stderr: "", exitCode: 0 }; if (typeof output === "string") return { stdout: output, stderr: "", exitCode: 0 }; if (typeof output === "object" && output !== null) { const obj = output as Record; return { stdout: String(obj.stdout ?? obj.output ?? ""), stderr: String(obj.stderr ?? ""), exitCode: Number(obj.exitCode ?? obj.exit_code ?? obj.code ?? 0), }; } return { stdout: String(output), stderr: "", exitCode: 0 }; } /** * Terminal-style command output preview. * Shows the command, exit code, and stdout/stderr with expand/collapse. */ export const CommandPreview = memo(({ part }: CommandPreviewProps) => { const [expanded, setExpanded] = useState(true); const input = part.state.input as Record | undefined; const command = typeof input?.command === "string" ? input.command : String(input ?? ""); const output = part.state.status === "completed" ? extractCommandOutput(part.state.output) : null; const isError = output ? output.exitCode !== 0 : part.state.status === "error"; const errorText = part.state.error; const lineCount = output?.stdout ? output.stdout.split("\n").length : 0; return ( } title="Command" description={command} meta={ output ? ( exit {output.exitCode} ) : null } > {part.state.status === "running" ? : null} {errorText ? : null} {expanded && output ? (
{output.stdout ? (
              {output.stdout}
            
) : null} {output.stderr ? (
              {output.stderr}
            
) : null}
) : null}
); }); CommandPreview.displayName = "CommandPreview";