{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "agent-activity",
  "title": "Agent activity",
  "description": "The agent's steps as a list: waiting, running, done or failed, with timings.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/manniche/agent-activity/agent-activity.tsx",
      "content": "import { Check, Circle, LoaderCircle, TriangleAlert } from 'lucide-react'\nimport { cn } from '@/lib/utils'\n\nexport type AgentStepStatus = 'pending' | 'running' | 'done' | 'error'\n\nexport type AgentStep = {\n  id: string\n  /** What the agent does, in plain words: \"Reading the invoice\". */\n  label: string\n  status: AgentStepStatus\n  /** A short detail under the label, e.g. a file name or an error. */\n  detail?: string\n  /** How long the step took, in milliseconds. Shown when the step is done. */\n  ms?: number\n}\n\nexport type AgentActivityProps = {\n  steps: AgentStep[]\n  title?: string\n  className?: string\n}\n\nconst ICON = {\n  pending: <Circle className=\"size-4 text-muted-foreground/60\" aria-hidden />,\n  running: <LoaderCircle className=\"size-4 animate-spin text-primary motion-reduce:animate-none\" aria-hidden />,\n  done: <Check className=\"size-4 text-success\" aria-hidden />,\n  error: <TriangleAlert className=\"size-4 text-destructive\" aria-hidden />,\n}\n\nconst SPOKEN: Record<AgentStepStatus, string> = { pending: 'waiting', running: 'in progress', done: 'done', error: 'failed' }\n\nfunction seconds(ms: number) {\n  return ms < 1000 ? `${ms} ms` : `${(ms / 1000).toFixed(1)} s`\n}\n\nexport function AgentActivity({ steps, title = 'Working', className }: AgentActivityProps) {\n  const done = steps.filter((s) => s.status === 'done').length\n  const running = steps.find((s) => s.status === 'running')\n\n  return (\n    <section className={cn('rounded-2xl border bg-card p-4 text-card-foreground shadow-sm', className)} aria-label={title}>\n      <header className=\"mb-3 flex items-baseline justify-between gap-4\">\n        <h3 className=\"font-medium\">{title}</h3>\n        <p className=\"text-sm text-muted-foreground tabular-nums\">\n          {done} of {steps.length}\n        </p>\n      </header>\n\n      {/* Only the step in progress is announced, so a screen reader is not flooded. */}\n      <p className=\"sr-only\" aria-live=\"polite\">\n        {running ? running.label : done === steps.length ? 'All steps done' : ''}\n      </p>\n\n      <ol className=\"relative\">\n        {steps.map((step, i) => (\n          <li key={step.id} className=\"relative flex gap-3 pb-4 last:pb-0\">\n            {i < steps.length - 1 && (\n              <span\n                className={cn(\n                  'absolute top-6 bottom-0 left-[9.5px] w-px transition-colors duration-300',\n                  step.status === 'done' ? 'bg-success/50' : 'bg-border',\n                )}\n                aria-hidden\n              />\n            )}\n            <span className=\"relative grid size-5 shrink-0 place-items-center pt-0.5\">{ICON[step.status]}</span>\n            <div className=\"min-w-0 flex-1\">\n              <p\n                className={cn(\n                  'text-[0.9375rem] leading-6 transition-colors duration-200',\n                  step.status === 'pending' && 'text-muted-foreground',\n                  step.status === 'running' && 'font-medium',\n                )}\n              >\n                {step.label}\n                <span className=\"sr-only\">, {SPOKEN[step.status]}</span>\n              </p>\n              {step.detail && (\n                <p className={cn('truncate text-sm', step.status === 'error' ? 'text-destructive' : 'text-muted-foreground')}>\n                  {step.detail}\n                </p>\n              )}\n            </div>\n            {step.status === 'done' && step.ms !== undefined && (\n              <span className=\"pt-0.5 text-sm text-muted-foreground tabular-nums\">{seconds(step.ms)}</span>\n            )}\n          </li>\n        ))}\n      </ol>\n    </section>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "categories": [
    "agent"
  ],
  "type": "registry:component"
}