{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tool-approval",
  "title": "Tool approval",
  "description": "Asks the person before the agent runs a tool, with the arguments in full and a clear mark on risky calls.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/manniche/tool-approval/tool-approval.tsx",
      "content": "import { Check, ChevronRight, ShieldAlert, X } from 'lucide-react'\nimport { useState } from 'react'\nimport { cn } from '@/lib/utils'\n\nexport type ToolApprovalState = 'pending' | 'approved' | 'denied'\n\nexport type ToolApprovalProps = {\n  /** The tool the agent wants to call, e.g. \"send_email\". */\n  tool: string\n  /** One sentence in plain words about what will happen. */\n  summary: string\n  /** The arguments, shown as JSON so nothing is hidden. */\n  args?: Record<string, unknown>\n  /** Mark a call that changes something outside the app. */\n  risky?: boolean\n  /** Controlled state. Leave it out and the card keeps its own. */\n  state?: ToolApprovalState\n  onApprove?: () => void\n  onDeny?: () => void\n  className?: string\n}\n\nexport function ToolApproval({ tool, summary, args, risky = false, state, onApprove, onDeny, className }: ToolApprovalProps) {\n  const [own, setOwn] = useState<ToolApprovalState>('pending')\n  const current = state ?? own\n\n  const decide = (next: Exclude<ToolApprovalState, 'pending'>) => {\n    setOwn(next)\n    if (next === 'approved') onApprove?.()\n    else onDeny?.()\n  }\n\n  return (\n    <section aria-label={`Approve ${tool}`} className={cn('overflow-hidden rounded-2xl border bg-card text-card-foreground shadow-sm', className)}>\n      <header className=\"flex items-start gap-3 p-4\">\n        <span\n          className={cn(\n            'grid size-9 shrink-0 place-items-center rounded-xl',\n            risky ? 'bg-destructive/10 text-destructive' : 'bg-accent text-accent-foreground',\n          )}\n          aria-hidden\n        >\n          <ShieldAlert className=\"size-5\" />\n        </span>\n        <div className=\"min-w-0\">\n          <p className=\"text-sm text-muted-foreground\">\n            The agent wants to use{' '}\n            <code className=\"rounded bg-muted px-1.5 py-0.5 font-mono text-[0.8125rem] text-foreground\">{tool}</code>\n          </p>\n          <p className=\"mt-1 font-medium text-pretty\">{summary}</p>\n        </div>\n      </header>\n\n      {args && (\n        <details className=\"group border-t\">\n          <summary className=\"flex min-h-11 cursor-pointer list-none items-center gap-1.5 px-4 text-sm text-muted-foreground transition-colors duration-150 hover:text-foreground [&::-webkit-details-marker]:hidden\">\n            <ChevronRight className=\"size-4 transition-transform duration-150 group-open:rotate-90\" aria-hidden />\n            Arguments\n          </summary>\n          <pre className=\"max-h-64 overflow-auto bg-muted/60 px-4 py-3 font-mono text-[0.8125rem] leading-5\">{JSON.stringify(args, null, 2)}</pre>\n        </details>\n      )}\n\n      <footer className=\"flex items-center justify-end gap-2 border-t bg-muted/40 p-3\" aria-live=\"polite\">\n        {current === 'pending' ? (\n          <>\n            <button\n              type=\"button\"\n              onClick={() => decide('denied')}\n              className=\"min-h-11 rounded-xl border bg-card px-4 text-sm font-medium transition-[background-color,transform] duration-150 ease-out-quint hover:bg-muted active:scale-[0.97]\"\n            >\n              Deny\n            </button>\n            <button\n              type=\"button\"\n              onClick={() => decide('approved')}\n              className={cn(\n                'min-h-11 rounded-xl px-4 text-sm font-medium transition-[filter,transform] duration-150 ease-out-quint hover:brightness-110 active:scale-[0.97]',\n                risky ? 'bg-destructive text-white' : 'bg-primary text-primary-foreground',\n              )}\n            >\n              {risky ? 'Approve anyway' : 'Approve'}\n            </button>\n          </>\n        ) : (\n          <p\n            className={cn(\n              'flex min-h-11 items-center gap-1.5 text-sm font-medium',\n              current === 'approved' ? 'text-success' : 'text-muted-foreground',\n            )}\n          >\n            {current === 'approved' ? <Check className=\"size-4\" aria-hidden /> : <X className=\"size-4\" aria-hidden />}\n            {current === 'approved' ? 'Approved' : 'Denied. The agent was told not to run it.'}\n          </p>\n        )}\n      </footer>\n    </section>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "categories": [
    "agent"
  ],
  "type": "registry:component"
}