{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "agent-limits-card",
  "title": "Agent Limits",
  "description": "Context-window usage ring and stacked bar plus plan rate-limit meters.",
  "dependencies": [
    "lucide-react@^1.33.0"
  ],
  "registryDependencies": [
    "https://components.exe.xyz/r/link-button.json",
    "https://components.exe.xyz/r/utils.json"
  ],
  "files": [
    {
      "path": "src/components/blocks/agent-limits-card.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { ChevronDown } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { LinkButton } from \"@/components/ui/link-button\"\n\nexport type AgentLimitSegment = {\n  label: string\n  tokens: number\n  color?: string\n  deferred?: boolean\n}\n\nexport type AgentLimitGroup = {\n  label: string\n  tokens: number\n  items: { label: string; tokens: number }[]\n}\n\nexport type AgentPlanLimit = {\n  label: string\n  used: number\n  resets: string\n}\n\nconst CHART = [\n  \"var(--chart-1)\",\n  \"var(--chart-2)\",\n  \"var(--chart-3)\",\n  \"var(--chart-4)\",\n  \"var(--chart-5)\",\n] as const\n\nfunction formatTokens(n: number) {\n  const abs = Math.abs(n)\n  if (abs >= 1_000_000) {\n    const m = n / 1_000_000\n    return `${Number.isInteger(m) ? m.toFixed(0) : m.toFixed(1)}M`\n  }\n  if (abs >= 1000) {\n    const k = n / 1000\n    return `${Number.isInteger(k) ? k.toFixed(0) : k.toFixed(1)}k`\n  }\n  return n.toLocaleString(\"en-US\")\n}\n\nfunction ringPath(cx: number, cy: number, r: number) {\n  return `M ${cx} ${cy - r} a ${r} ${r} 0 1 1 0 ${r * 2} a ${r} ${r} 0 1 1 0 ${-r * 2}`\n}\n\nexport function AgentLimitsCard({\n  context,\n  plan,\n  planHref,\n  limits,\n  defaultExpanded = false,\n  onExpandedChange,\n  className,\n}: {\n  context: {\n    max: number\n    segments: AgentLimitSegment[]\n    groups?: AgentLimitGroup[]\n  }\n  plan: string\n  planHref?: string\n  limits: AgentPlanLimit[]\n  defaultExpanded?: boolean\n  onExpandedChange?: (open: boolean) => void\n  className?: string\n}) {\n  const [expanded, setExpanded] = React.useState(defaultExpanded)\n  const active = context.segments.filter((seg) => !seg.deferred)\n  const deferred = context.segments.filter((seg) => seg.deferred)\n  const used = active.reduce((sum, seg) => sum + seg.tokens, 0)\n  const remaining = Math.max(0, context.max - used)\n  const pct = context.max > 0 ? Math.round((used / context.max) * 100) : 0\n  const remainingPct = Math.max(0, 100 - pct)\n  const circ = 2 * Math.PI * 36\n\n  const setOpen = (next: boolean) => {\n    setExpanded(next)\n    onExpandedChange?.(next)\n  }\n\n  const barLabel = active\n    .map((seg) => {\n      const share =\n        context.max > 0 ? Math.round((seg.tokens / context.max) * 100) : 0\n      return `${seg.label} ${formatTokens(seg.tokens)}, ${share} percent`\n    })\n    .join(\". \")\n\n  return (\n    <section\n      data-slot=\"agent-limits-card\"\n      className={cn(\n        \"flex w-full max-w-md flex-col rounded-[2px] border border-border bg-card\",\n        className\n      )}\n    >\n      <div className=\"flex items-center gap-4 border-b border-border px-3 py-3\">\n        <svg\n          viewBox=\"0 0 88 88\"\n          className=\"size-20 shrink-0\"\n          role=\"img\"\n          aria-label={`${formatTokens(remaining)} remaining of ${formatTokens(context.max)}`}\n        >\n          <path\n            d={ringPath(44, 44, 36)}\n            fill=\"none\"\n            stroke=\"var(--muted)\"\n            strokeWidth={8}\n          />\n          <path\n            d={ringPath(44, 44, 36)}\n            fill=\"none\"\n            stroke=\"var(--chart-1)\"\n            strokeWidth={8}\n            strokeDasharray={circ}\n            strokeDashoffset={circ * (1 - Math.min(1, used / context.max))}\n            strokeLinecap=\"butt\"\n            transform=\"rotate(-90 44 44)\"\n          />\n          <text\n            x=\"44\"\n            y=\"42\"\n            textAnchor=\"middle\"\n            fill=\"var(--foreground)\"\n            fontSize=\"13\"\n            fontFamily=\"var(--font-heading)\"\n            fontWeight={600}\n          >\n            {formatTokens(remaining)}\n          </text>\n          <text\n            x=\"44\"\n            y=\"56\"\n            textAnchor=\"middle\"\n            fill=\"var(--muted-foreground)\"\n            fontSize=\"8\"\n            fontFamily=\"var(--font-mono)\"\n          >\n            left · {remainingPct}%\n          </text>\n        </svg>\n        <div className=\"min-w-0 flex-1\">\n          <p className=\"font-heading text-sm font-medium\">Context window</p>\n          <p className=\"font-mono text-[11px] text-muted-foreground\">\n            {formatTokens(used)} / {formatTokens(context.max)} ({pct}%)\n          </p>\n        </div>\n      </div>\n\n      <div\n        role=\"region\"\n        aria-label=\"Context window\"\n        className=\"flex flex-col gap-3 px-3 py-3\"\n      >\n        <div\n          role=\"img\"\n          aria-label={`Context window stacked bar. ${barLabel}`}\n          className=\"flex h-2.5 w-full overflow-hidden rounded-[2px] bg-muted\"\n        >\n          {active.map((seg, index) => (\n            <div\n              key={seg.label}\n              className=\"h-full min-w-px\"\n              style={{\n                width: `${context.max > 0 ? (seg.tokens / context.max) * 100 : 0}%`,\n                background: seg.color ?? CHART[index % CHART.length],\n              }}\n            />\n          ))}\n        </div>\n        <ul className=\"flex flex-col gap-1.5\">\n          {active.map((seg, index) => {\n            const share =\n              context.max > 0 ? Math.round((seg.tokens / context.max) * 100) : 0\n            return (\n              <li\n                key={seg.label}\n                className=\"flex items-baseline justify-between gap-3 text-sm\"\n              >\n                <span className=\"flex min-w-0 items-center gap-2\">\n                  <span\n                    className=\"size-1.5 shrink-0 rounded-[1px]\"\n                    style={{\n                      background: seg.color ?? CHART[index % CHART.length],\n                    }}\n                  />\n                  <span className=\"truncate\">{seg.label}</span>\n                </span>\n                <span className=\"font-mono text-[11px] text-muted-foreground tabular-nums\">\n                  {formatTokens(seg.tokens)} · {share}%\n                </span>\n              </li>\n            )\n          })}\n          {deferred.map((seg) => (\n            <li\n              key={seg.label}\n              className=\"flex items-baseline justify-between gap-3 text-sm text-muted-foreground\"\n            >\n              <span className=\"truncate\">{seg.label}</span>\n              <span className=\"font-mono text-[11px] tabular-nums\">\n                , {formatTokens(seg.tokens)}\n              </span>\n            </li>\n          ))}\n        </ul>\n\n        {context.groups && context.groups.length > 0 ? (\n          <div className=\"flex flex-col gap-1\">\n            <button\n              type=\"button\"\n              aria-expanded={expanded}\n              onClick={() => setOpen(!expanded)}\n              className=\"flex items-center gap-1 self-start rounded-[2px] text-xs text-muted-foreground outline-none hover:text-foreground focus-visible:ring-3 focus-visible:ring-ring/50\"\n            >\n              Breakdown\n              <ChevronDown\n                className={cn(\n                  \"size-3.5 transition-transform\",\n                  expanded && \"rotate-180\"\n                )}\n              />\n            </button>\n            {expanded\n              ? context.groups.map((group) => (\n                  <details key={group.label} className=\"group/details\">\n                    <summary className=\"flex cursor-pointer list-none items-baseline justify-between gap-3 rounded-[2px] py-1 text-sm outline-none focus-visible:ring-3 focus-visible:ring-ring/50 [&::-webkit-details-marker]:hidden\">\n                      <span>{group.label}</span>\n                      <span className=\"font-mono text-[11px] text-muted-foreground\">\n                        {formatTokens(group.tokens)} / {group.items.length}\n                      </span>\n                    </summary>\n                    <ul className=\"mb-1 ml-3 flex flex-col gap-1 border-l border-border pl-3\">\n                      {group.items.map((item) => (\n                        <li\n                          key={item.label}\n                          className=\"flex items-baseline justify-between gap-3 text-xs text-muted-foreground\"\n                        >\n                          <span className=\"truncate\">{item.label}</span>\n                          <span className=\"font-mono tabular-nums\">\n                            {formatTokens(item.tokens)}\n                          </span>\n                        </li>\n                      ))}\n                    </ul>\n                  </details>\n                ))\n              : null}\n          </div>\n        ) : null}\n      </div>\n\n      <div className=\"flex flex-col gap-3 border-t border-border px-3 py-3\">\n        <div className=\"flex items-baseline justify-between gap-3\">\n          <h3 className=\"font-heading text-sm font-medium\">\n            Plan usage limits · {plan}\n          </h3>\n          {planHref ? (\n            <LinkButton href={planHref} size=\"xs\" variant=\"secondary\">\n              View plan\n            </LinkButton>\n          ) : null}\n        </div>\n        <ul className=\"flex flex-col gap-3\">\n          {limits.map((limit) => {\n            const value = Math.min(100, Math.max(0, limit.used))\n            return (\n              <li key={limit.label} className=\"flex flex-col gap-1\">\n                <div className=\"flex items-baseline justify-between gap-3\">\n                  <span className=\"text-sm\">{limit.label}</span>\n                  <span className=\"font-mono text-[11px] text-muted-foreground tabular-nums\">\n                    {value}%\n                  </span>\n                </div>\n                <div\n                  role=\"meter\"\n                  aria-label={limit.label}\n                  aria-valuemin={0}\n                  aria-valuemax={100}\n                  aria-valuenow={value}\n                  className=\"h-1 w-full overflow-hidden rounded-[2px] bg-muted\"\n                >\n                  <div\n                    className=\"h-full bg-primary\"\n                    style={{ width: `${value}%` }}\n                  />\n                </div>\n                <p className=\"font-mono text-[11px] text-muted-foreground\">\n                  {limit.resets}\n                </p>\n              </li>\n            )\n          })}\n        </ul>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:block"
    }
  ],
  "type": "registry:block"
}