{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tool-call-stack",
  "type": "registry:ui",
  "title": "Tool call stack",
  "description": "Collects search, write, command, and failure states into an inspectable execution record.",
  "dependencies": [
    "motion"
  ],
  "categories": [
    "agent"
  ],
  "docs": "https://motion-lexicon.pages.dev/en/components/tool-call-stack/",
  "meta": {
    "engines": [
      "motion"
    ],
    "runtimeCost": "light",
    "signature": "Execution records expand and resolve by tool state"
  },
  "files": [
    {
      "path": "src/registry/components/tool-call-stack.tsx",
      "type": "registry:ui",
      "target": "components/motion-lexicon/tool-call-stack.tsx",
      "content": "\"use client\";\n\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { useState } from \"react\";\n\nexport type ToolCall = {\n  id: string;\n  name: string;\n  summary: string;\n  detail?: string;\n  status: \"running\" | \"complete\" | \"failed\";\n  duration?: string;\n  kind?: \"search\" | \"code\" | \"file\" | \"command\";\n};\nexport type ToolCallStackProps = {\n  calls: readonly ToolCall[];\n  label?: string;\n  className?: string;\n};\n\nconst marks = { search: \"⌕\", code: \"<>\", file: \"□\", command: \">_\" } as const;\n\nexport function ToolCallStack({\n  calls,\n  label = \"Tool calls\",\n  className = \"\",\n}: ToolCallStackProps) {\n  const [open, setOpen] = useState<string[]>(() =>\n    calls.filter((call) => call.status === \"running\").map((call) => call.id),\n  );\n  const reduced = useReducedMotion();\n  const complete = calls.filter((call) => call.status === \"complete\").length;\n\n  return (\n    <section\n      className={`w-full overflow-hidden rounded-[10px] border border-neutral-200 bg-white text-neutral-950 dark:border-white/10 dark:bg-[#1b1b1b] dark:text-neutral-50 ${className}`}\n    >\n      <header className=\"flex min-h-12 items-center gap-3 border-b border-neutral-100 px-4 dark:border-white/8\">\n        <span className=\"text-[11px] font-medium text-neutral-600 dark:text-neutral-300\">\n          {label}\n        </span>\n        <span className=\"ml-auto rounded-full bg-neutral-100 px-2 py-1 text-[9px] text-neutral-500 dark:bg-white/5 dark:text-neutral-400\">\n          {complete}/{calls.length}\n        </span>\n      </header>\n      <div className=\"p-2\">\n        {calls.map((call) => {\n          const expanded = open.includes(call.id);\n          return (\n            <div\n              key={call.id}\n              className=\"overflow-hidden rounded-lg border border-transparent hover:border-neutral-100 dark:hover:border-white/8\"\n            >\n              <button\n                type=\"button\"\n                aria-expanded={expanded}\n                onClick={() =>\n                  setOpen((current) =>\n                    current.includes(call.id)\n                      ? current.filter((id) => id !== call.id)\n                      : [...current, call.id],\n                  )\n                }\n                className=\"flex min-h-12 w-full items-center gap-3 px-3 text-left outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-blue-600\"\n              >\n                <span\n                  className={`relative grid size-8 shrink-0 place-items-center rounded-lg border font-mono text-[9px] ${call.status === \"complete\" ? \"border-emerald-200 text-emerald-700 dark:border-emerald-500/30 dark:text-emerald-300\" : call.status === \"failed\" ? \"border-red-200 text-red-600 dark:border-red-500/30 dark:text-red-300\" : \"border-neutral-300 text-neutral-800 dark:border-white/20 dark:text-neutral-200\"}`}\n                >\n                  {marks[call.kind ?? \"command\"]}\n                  {call.status === \"running\" ? (\n                    <motion.i\n                      className=\"absolute inset-0 rounded-lg border border-neutral-500/50\"\n                      animate={\n                        reduced ? undefined : { opacity: [0.25, 1, 0.25] }\n                      }\n                      transition={{ duration: 1.2, repeat: Infinity }}\n                    />\n                  ) : null}\n                </span>\n                <span className=\"min-w-0 flex-1\">\n                  <strong className=\"block truncate text-[12px] font-medium\">\n                    {call.name}\n                  </strong>\n                  <span className=\"block truncate text-[10px] text-neutral-500 dark:text-neutral-400\">\n                    {call.summary}\n                  </span>\n                </span>\n                {call.duration ? (\n                  <code className=\"text-[9px] tabular-nums text-neutral-400\">\n                    {call.duration}\n                  </code>\n                ) : null}\n              </button>\n              <AnimatePresence initial={false}>\n                {expanded && call.detail ? (\n                  <motion.pre\n                    initial={reduced ? false : { height: 0, opacity: 0 }}\n                    animate={{ height: \"auto\", opacity: 1 }}\n                    exit={{ height: 0, opacity: 0 }}\n                    className=\"mx-3 mb-3 overflow-auto rounded-lg bg-neutral-950 p-3 text-[9px] leading-5 text-neutral-300\"\n                  >\n                    <code>{call.detail}</code>\n                  </motion.pre>\n                ) : null}\n              </AnimatePresence>\n            </div>\n          );\n        })}\n      </div>\n    </section>\n  );\n}\n"
    }
  ]
}
