{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "stopped-run",
  "title": "Stopped Run",
  "description": "What the thread says after an answer ended early, keeping what it had already written.",
  "dependencies": [
    "lucide-react@^1.31.0"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/default/stopped-run/stopped-run.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { CircleAlert, Hand, RotateCw, Timer } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport type StoppedReason = \"stopped\" | \"error\" | \"limit\" | \"timeout\"\n\nexport type StoppedRunProps = Omit<\n  React.HTMLAttributes<HTMLDivElement>,\n  \"children\"\n> & {\n  reason?: StoppedReason\n  /** What arrived before it ended. Kept, not thrown away. */\n  children?: React.ReactNode\n  /** Replaces the default sentence for the reason. */\n  message?: string\n  /** Seconds it ran for. */\n  elapsed?: number\n  onRetry?: () => void\n  onResume?: () => void\n  retryLabel?: string\n  resumeLabel?: string\n}\n\nconst wording: Record<StoppedReason, string> = {\n  stopped: \"You stopped this answer.\",\n  error: \"The answer stopped because something went wrong.\",\n  limit: \"The answer reached its length limit.\",\n  timeout: \"The answer took too long and was cut off.\",\n}\n\nconst marks: Record<StoppedReason, React.ComponentType<{ size?: number }>> = {\n  stopped: Hand,\n  error: CircleAlert,\n  limit: CircleAlert,\n  timeout: Timer,\n}\n\nfunction formatSeconds(seconds: number) {\n  return seconds < 60\n    ? `${seconds < 10 ? seconds.toFixed(1) : Math.round(seconds)}s`\n    : `${Math.floor(seconds / 60)}m ${Math.round(seconds % 60)}s`\n}\n\n/**\n * What the thread says after an answer ended early, with whatever it had\n * already written kept above the line.\n *\n * The partial text is marked as incomplete rather than left to be read as an\n * answer, because half a sentence delivered in the same voice as a finished\n * one is the failure this component exists to prevent.\n */\nexport function StoppedRun({\n  reason = \"stopped\",\n  children,\n  message,\n  elapsed,\n  onRetry,\n  onResume,\n  retryLabel = \"Try again\",\n  resumeLabel = \"Carry on\",\n  className,\n  ...rootProps\n}: StoppedRunProps) {\n  const Mark = marks[reason]\n  const said = message ?? wording[reason]\n\n  return (\n    <div\n      data-slot=\"stopped-run\"\n      data-reason={reason}\n      className={cn(\"w-full\", className)}\n      {...rootProps}\n    >\n      {children ? (\n        <div\n          data-slot=\"stopped-run-partial\"\n          role=\"group\"\n          aria-label=\"Incomplete answer\"\n          className=\"text-foreground [mask-image:linear-gradient(to_bottom,black_60%,color-mix(in_oklab,black_45%,transparent))] text-sm\"\n        >\n          {children}\n        </div>\n      ) : null}\n\n      <div\n        className={cn(\n          \"border-border text-muted-foreground mt-2 flex flex-wrap items-center gap-x-3 gap-y-2 border-t pt-2 text-xs\",\n          reason === \"error\" && \"text-destructive\"\n        )}\n      >\n        <Mark aria-hidden=\"true\" size={14} />\n        <span className=\"min-w-0\">\n          {said}\n          {elapsed !== undefined ? (\n            <span className=\"opacity-70\">\n              {\" \"}\n              Ran for {formatSeconds(elapsed)}.\n            </span>\n          ) : null}\n        </span>\n\n        <span className=\"ms-auto flex items-center gap-1\">\n          {onResume ? (\n            <button\n              type=\"button\"\n              onClick={onResume}\n              className=\"text-foreground hover:bg-muted focus-visible:ring-ring inline-flex min-h-8 items-center rounded-md px-2.5 font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none motion-reduce:transition-none\"\n            >\n              {resumeLabel}\n            </button>\n          ) : null}\n          {onRetry ? (\n            <button\n              type=\"button\"\n              onClick={onRetry}\n              className=\"text-foreground hover:bg-muted focus-visible:ring-ring inline-flex min-h-8 items-center gap-1.5 rounded-md px-2.5 font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none motion-reduce:transition-none\"\n            >\n              <RotateCw aria-hidden=\"true\" size={13} />\n              {retryLabel}\n            </button>\n          ) : null}\n        </span>\n      </div>\n\n      <span aria-live=\"polite\" className=\"sr-only\">\n        {said}\n      </span>\n    </div>\n  )\n}\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "ai",
    "agent",
    "chat",
    "feedback",
    "error"
  ],
  "type": "registry:ui"
}