A command the agent ran: live output with stderr marked, exit code, run time, copy and stop.
Set your access key from API keys as NEXTUI_TOKEN in .env.local and add the @nextui namespace below to components.json once. Then every item installs by name. Each install counts as a copy on a free account.
$pnpm dlx shadcn@latest add @nextui/terminal-output
1{2"registries": {3"@nextui": {4"url": "https://nextui.dev/r/{name}.json",5"headers": { "Authorization": "Bearer ${NEXTUI_TOKEN}" }6}7}8}
1"use client";23import type { UIMessage } from "ai";4import { TerminalOutput } from "@/components/nextui/terminal-output";56// Render a "bash" tool part from useChat messages.7// Stream output from your tool with preliminary results (async *execute yields).8export function BashPart({ part }: { part: Extract<UIMessage["parts"][number], { type: `tool-${string}` }> }) {9const input = part.input as { command?: string } | undefined;10const output = part.output as { lines: string[]; exitCode?: number; ms?: number } | undefined;11const done = part.state === "output-available" && part.preliminary !== true;1213return (14<TerminalOutput15command={input?.command ?? ""}16lines={output?.lines ?? []}17status={!done ? "running" : output?.exitCode ? "error" : "success"}18exitCode={output?.exitCode ?? 0}19duration={output?.ms ?? 0}20/>21);22}
| Prop | Type | Default | Description |
|---|---|---|---|
| command | string | – | The command the agent ran |
| cwd | string | "~/app" | Working directory, shown before the prompt |
| lines | (string | { text: string; stream?: "stdout" | "stderr" })[] | – | Output so far. Strings are stdout; stderr lines are tinted and announced as stderr |
| status | "running" | "success" | "error" | "success" | Running shows a live pill and cursor and keeps the newest line in view |
| exitCode | number | 0 | Shown once the command has finished |
| duration | number | – | Run time in ms |
| onStop | () => void | – | Called by the stop button while running. Leave out to hide it |
| maxLines | number | 12 | Lines shown once finished before a Show all button; the tail is kept |
| open | boolean | – | Controlled open state of the output |
| defaultOpen | boolean | true | Starting open state when uncontrolled |
| onOpenChange | (open: boolean) => void | – | Called when the header is clicked |
| autoPlay | boolean | false | Loop a scripted test run, for demos |
| className | string | – | Extra classes on the card |
Sign in to see the code
Preview it freely. A free account copies code and prompts a few times a day.