{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tool",
  "title": "Tool",
  "description": "A tool call: name, live status, timing, parameters and result.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "https://ui.cuelark.com/r/theme.json",
    "https://ui.cuelark.com/r/collapsible.json",
    "https://ui.cuelark.com/r/motion.json",
    "https://ui.cuelark.com/r/spinner.json",
    "https://ui.cuelark.com/r/text-shimmer.json"
  ],
  "files": [
    {
      "path": "src/registry/cuelark/ui/tool.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { AlertTriangleIcon, CheckIcon, ChevronDownIcon, CircleDashedIcon, WrenchIcon } from \"lucide-react\";\n\nimport { flash, pop } from \"@/lib/motion\";\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from \"@/registry/cuelark/ui/collapsible\";\nimport { Spinner } from \"@/registry/cuelark/ui/spinner\";\nimport { TextShimmer } from \"@/registry/cuelark/ui/text-shimmer\";\nimport { cn } from \"@/lib/utils\";\n\ntype ToolStatus = \"pending\" | \"running\" | \"success\" | \"error\";\n\ntype ToolProps = Omit<React.ComponentProps<typeof Collapsible>, \"children\"> & {\n  name: string;\n  status?: ToolStatus;\n  /** Arguments the agent called the tool with. Objects are pretty-printed. */\n  input?: unknown;\n  /** What the tool returned (or the error). */\n  output?: unknown;\n  /** Seconds the call took. */\n  duration?: number;\n  icon?: React.ReactNode;\n};\n\nconst print = (v: unknown) => (typeof v === \"string\" ? v : JSON.stringify(v, null, 2));\n\n/**\n * One tool call, compact by default: the mono tool name, a live status (shimmer while running), and timing. Expand\n * for the exact parameters and result. Errors open themselves, so failures are never hidden.\n */\nfunction Tool({ name, status = \"success\", input, output, duration, icon, className, defaultOpen, ...props }: ToolProps) {\n  const ref = React.useRef<HTMLDivElement>(null);\n  const prev = React.useRef(status);\n  React.useLayoutEffect(() => {\n    if (prev.current === status) return;\n    const was = prev.current;\n    prev.current = status;\n    if (was === \"running\" || was === \"pending\") {\n      flash(ref.current);\n      pop(ref.current?.querySelector('[data-part=\"status\"]') ?? null);\n    }\n  }, [status]);\n  return (\n    <Collapsible\n      ref={ref}\n      data-slot=\"tool\"\n      data-status={status}\n      defaultOpen={defaultOpen ?? status === \"error\"}\n      className={cn(\"group/tool overflow-hidden rounded-xl border border-border bg-card text-sm data-[status=error]:border-destructive/40\", className)}\n      {...props}\n    >\n      <CollapsibleTrigger className=\"flex w-full items-center gap-2.5 px-3 py-2.5 text-left outline-none hover:bg-muted/50 focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:ring-inset\">\n        <span className=\"grid size-6 place-items-center rounded-md bg-muted text-muted-foreground [&_svg]:size-3.5\">{icon ?? <WrenchIcon />}</span>\n        <span className=\"truncate font-mono text-[0.8125rem]\">{status === \"running\" ? <TextShimmer>{name}</TextShimmer> : name}</span>\n        <span className=\"ms-auto flex items-center gap-2 text-xs text-muted-foreground\">\n          {duration != null && status !== \"running\" && <span className=\"font-mono tabular-nums\">{duration.toFixed(1)}s</span>}\n          <span data-part=\"status\" className=\"grid\">\n            <StatusMark status={status} />\n          </span>\n          <ChevronDownIcon className=\"size-4 transition-transform duration-200 ease-cue group-data-[state=open]/tool:rotate-180\" />\n        </span>\n      </CollapsibleTrigger>\n      <CollapsibleContent>\n        <div className=\"grid gap-3 border-t border-border bg-muted/30 p-3\">\n          {input !== undefined && (\n            <section className=\"grid gap-1.5\">\n              <h4 className=\"cue-label\">Parameters</h4>\n              <pre className=\"max-h-48 overflow-auto rounded-lg bg-background p-3 font-mono text-xs leading-relaxed ring-1 ring-border\">{print(input)}</pre>\n            </section>\n          )}\n          {output !== undefined && (\n            <section className=\"grid gap-1.5\">\n              <h4 className={cn(\"cue-label\", status === \"error\" && \"text-destructive\")}>{status === \"error\" ? \"Error\" : \"Result\"}</h4>\n              <pre className={cn(\"max-h-48 overflow-auto rounded-lg bg-background p-3 font-mono text-xs leading-relaxed ring-1 ring-border\", status === \"error\" && \"text-destructive ring-destructive/30\")}>{print(output)}</pre>\n            </section>\n          )}\n        </div>\n      </CollapsibleContent>\n    </Collapsible>\n  );\n}\n\nfunction StatusMark({ status }: { status: ToolStatus }) {\n  if (status === \"running\") return <Spinner size=\"sm\" className=\"text-foreground\" label=\"Running\" />;\n  if (status === \"pending\") return <CircleDashedIcon className=\"size-4\" aria-label=\"Pending\" />;\n  if (status === \"error\") return <AlertTriangleIcon className=\"size-4 text-destructive\" aria-label=\"Failed\" />;\n  return (\n    <span className=\"grid size-4 place-items-center rounded-full bg-signal text-signal-foreground\" aria-label=\"Done\">\n      <CheckIcon className=\"size-2.5\" strokeWidth={3.5} />\n    </span>\n  );\n}\n\nexport { Tool };\nexport type { ToolProps, ToolStatus };\n",
      "type": "registry:ui"
    }
  ],
  "docs": "Docs and examples: https://ui.cuelark.com/components/tool",
  "categories": [
    "agents"
  ],
  "type": "registry:ui"
}