{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "subagent-tree",
  "title": "Subagent Tree",
  "description": "Several agents working at once, nested under whoever handed the work down.",
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/default/subagent-tree/subagent-tree.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport type AgentRunStatus = \"queued\" | \"running\" | \"done\" | \"failed\"\n\nexport type AgentRun = {\n  id: string\n  label: string\n  status?: AgentRunStatus\n  /** What it is doing, or what it found. */\n  detail?: React.ReactNode\n  /** Seconds it has taken. */\n  duration?: number\n  children?: readonly AgentRun[]\n}\n\nexport type SubagentTreeProps = Omit<\n  React.HTMLAttributes<HTMLDivElement>,\n  \"children\"\n> & {\n  runs: readonly AgentRun[]\n  label?: string\n}\n\nconst wording: Record<AgentRunStatus, string> = {\n  queued: \"queued\",\n  running: \"running\",\n  done: \"done\",\n  failed: \"failed\",\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\nfunction tally(runs: readonly AgentRun[]) {\n  let running = 0\n  let done = 0\n  let failed = 0\n  let total = 0\n\n  const walk = (list: readonly AgentRun[]) => {\n    for (const run of list) {\n      total += 1\n      const status = run.status ?? \"done\"\n      if (status === \"running\") running += 1\n      if (status === \"done\") done += 1\n      if (status === \"failed\") failed += 1\n      if (run.children) walk(run.children)\n    }\n  }\n\n  walk(runs)\n  return { running, done, failed, total }\n}\n\nfunction Branch({ runs, depth }: { runs: readonly AgentRun[]; depth: number }) {\n  return (\n    <ul\n      className={cn(\n        \"space-y-1\",\n        depth > 0 &&\n          \"border-border relative ms-[7px] border-s ps-4 before:absolute before:-start-px before:top-0 before:h-2 before:w-px\"\n      )}\n    >\n      {runs.map((run) => {\n        const status = run.status ?? \"done\"\n\n        return (\n          <li key={run.id} data-status={status}>\n            <p className=\"flex items-baseline gap-2 text-sm\">\n              <span\n                aria-hidden=\"true\"\n                className={cn(\n                  \"relative top-[3px] size-[9px] shrink-0 rounded-full\",\n                  status === \"running\" &&\n                    \"bg-primary animate-pulse motion-reduce:animate-none\",\n                  status === \"done\" && \"bg-muted-foreground/40\",\n                  status === \"failed\" && \"bg-destructive\",\n                  status === \"queued\" && \"border-muted-foreground/40 border\"\n                )}\n              />\n              <span\n                className={cn(\n                  status === \"queued\"\n                    ? \"text-muted-foreground\"\n                    : \"text-foreground\"\n                )}\n              >\n                {run.label}\n              </span>\n              <span className=\"sr-only\">, {wording[status]}</span>\n              {run.duration !== undefined ? (\n                <span className=\"text-muted-foreground shrink-0 font-mono text-[0.6875rem] tabular-nums\">\n                  {formatSeconds(run.duration)}\n                </span>\n              ) : null}\n            </p>\n\n            {run.detail ? (\n              <div className=\"text-muted-foreground ms-[17px] text-[0.8125rem] leading-relaxed\">\n                {run.detail}\n              </div>\n            ) : null}\n\n            {run.children?.length ? (\n              <div className=\"mt-1\">\n                <Branch runs={run.children} depth={depth + 1} />\n              </div>\n            ) : null}\n          </li>\n        )\n      })}\n    </ul>\n  )\n}\n\n/**\n * Several agents working at once, nested under whichever one handed the work\n * down, each with its own state and the time it has taken.\n *\n * It is nested lists rather than a tree widget. Nothing here is expanded,\n * selected or navigated, and announcing \"tree, level 2\" over work that is only\n * being watched buys a keyboard interaction nobody asked for.\n */\nexport function SubagentTree({\n  runs,\n  label = \"Agents\",\n  className,\n  ...rootProps\n}: SubagentTreeProps) {\n  const counts = tally(runs)\n\n  const summary =\n    counts.running > 0\n      ? `${counts.running} of ${counts.total} agents running`\n      : counts.failed > 0\n        ? `${counts.total} agents finished, ${counts.failed} failed`\n        : `${counts.total} agents finished`\n\n  return (\n    <div\n      data-slot=\"subagent-tree\"\n      data-running={counts.running > 0 ? \"\" : undefined}\n      className={cn(\n        \"border-border bg-background w-full rounded-xl border p-3\",\n        className\n      )}\n      {...rootProps}\n    >\n      <p className=\"text-muted-foreground mb-2 flex items-baseline gap-2 text-xs\">\n        <span className=\"font-medium\">{label}</span>\n        <span className=\"ms-auto tabular-nums\">\n          {counts.done}/{counts.total} done\n          {counts.failed > 0 ? (\n            <span className=\"text-destructive ms-2\">\n              {counts.failed} failed\n            </span>\n          ) : null}\n        </span>\n      </p>\n\n      <Branch runs={runs} depth={0} />\n\n      <span aria-live=\"polite\" className=\"sr-only\">\n        {summary}\n      </span>\n    </div>\n  )\n}\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "ai",
    "agent",
    "status",
    "tree",
    "feedback"
  ],
  "type": "registry:ui"
}