{
  "name": "agent-timeline",
  "dependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "path": "agent-timeline.tsx",
      "content": "\"use client\";\r\n\r\nimport { css, keyframes, themeVars as theme } from \"@yugnex/core\";\r\nimport type { HTMLAttributes, ReactNode } from \"react\";\r\n\r\nexport type AgentStepStatus = \"pending\" | \"running\" | \"success\" | \"error\" | \"skipped\";\r\n\r\nconst spin = keyframes({ from: { transform: \"rotate(0deg)\" }, to: { transform: \"rotate(360deg)\" } });\r\nconst pulse = keyframes({\r\n  \"0%, 100%\": { boxShadow: `0 0 0 0 ${theme.color.accent}` },\r\n  \"50%\": { boxShadow: `0 0 0 4px ${theme.color.accent}` },\r\n});\r\n\r\nconst listClass = css({\r\n  display: \"flex\",\r\n  flexDirection: \"column\",\r\n  margin: 0,\r\n  padding: 0,\r\n  listStyle: \"none\",\r\n  fontFamily: theme.fontFamily.sans,\r\n});\r\n\r\nconst stepClass = css({\r\n  position: \"relative\",\r\n  display: \"grid\",\r\n  gridTemplateColumns: \"1.5rem 1fr\",\r\n  gap: theme.space[3],\r\n  paddingBottom: theme.space[4],\r\n  // The rail is drawn as a pseudo-element on each step rather than one\r\n  // absolutely-positioned line, so it automatically spans exactly the rendered\r\n  // steps — no measuring, and it can't overshoot past the last marker.\r\n  \"&:not(:last-child)::before\": {\r\n    content: '\"\"',\r\n    position: \"absolute\",\r\n    left: \"0.6875rem\",\r\n    top: \"1.5rem\",\r\n    bottom: 0,\r\n    width: \"1px\",\r\n    backgroundColor: theme.color.border,\r\n  },\r\n  \"&:last-child\": { paddingBottom: 0 },\r\n});\r\n\r\nconst markerClass = css({\r\n  position: \"relative\",\r\n  zIndex: 1,\r\n  display: \"flex\",\r\n  alignItems: \"center\",\r\n  justifyContent: \"center\",\r\n  width: \"1.5rem\",\r\n  height: \"1.5rem\",\r\n  borderRadius: \"9999px\",\r\n  border: `2px solid ${theme.color.border}`,\r\n  backgroundColor: theme.color.background,\r\n  flexShrink: 0,\r\n  '&[data-status=\"running\"]': {\r\n    borderColor: theme.color.primary,\r\n    animation: `${pulse} 1.8s ease-in-out infinite`,\r\n  },\r\n  '&[data-status=\"success\"]': { borderColor: theme.color.success, backgroundColor: theme.color.success },\r\n  '&[data-status=\"error\"]': { borderColor: theme.color.destructive, backgroundColor: theme.color.destructive },\r\n  '&[data-status=\"skipped\"]': { opacity: 0.5 },\r\n});\r\n\r\nconst spinnerClass = css({\r\n  width: \"10px\",\r\n  height: \"10px\",\r\n  borderRadius: \"9999px\",\r\n  border: `2px solid ${theme.color.primary}`,\r\n  borderTopColor: \"transparent\",\r\n  animation: `${spin} 0.7s linear infinite`,\r\n});\r\n\r\nconst dotClass = css({\r\n  width: \"6px\",\r\n  height: \"6px\",\r\n  borderRadius: \"9999px\",\r\n  backgroundColor: theme.color.mutedForeground,\r\n});\r\n\r\nconst bodyClass = css({ minWidth: 0, paddingTop: \"1px\" });\r\n\r\nconst headerRowClass = css({\r\n  display: \"flex\",\r\n  alignItems: \"baseline\",\r\n  gap: theme.space[2],\r\n  flexWrap: \"wrap\",\r\n});\r\n\r\nconst titleClass = css({\r\n  margin: 0,\r\n  fontSize: theme.fontSize.sm,\r\n  fontWeight: theme.fontWeight.medium,\r\n  color: theme.color.foreground,\r\n  '[data-status=\"skipped\"] &': { color: theme.color.mutedForeground, textDecoration: \"line-through\" },\r\n});\r\n\r\nconst metaClass = css({\r\n  fontSize: theme.fontSize.xs,\r\n  color: theme.color.mutedForeground,\r\n  fontVariantNumeric: \"tabular-nums\",\r\n});\r\n\r\nconst detailClass = css({\r\n  marginTop: theme.space[1.5],\r\n  fontSize: theme.fontSize.sm,\r\n  lineHeight: theme.lineHeight.sm,\r\n  color: theme.color.mutedForeground,\r\n});\r\n\r\nexport interface AgentStep {\r\n  id: string;\r\n  title: ReactNode;\r\n  status?: AgentStepStatus;\r\n  /** Duration, timestamp, token count — anything short and right-aligned to the title. */\r\n  meta?: ReactNode;\r\n  /** Expanded content: reasoning, a <ToolCall>, output, an error. */\r\n  detail?: ReactNode;\r\n}\r\n\r\nexport interface AgentTimelineProps extends HTMLAttributes<HTMLOListElement> {\r\n  steps: AgentStep[];\r\n}\r\n\r\n/**\r\n * A vertical trace of an agent run — plan, tool calls, observations, answer —\r\n * with a status marker per step and a rail connecting them. This is what turns\r\n * \"the agent did something for 40 seconds\" into a reviewable record.\r\n */\r\nexport function AgentTimeline({ steps, className, ...props }: AgentTimelineProps) {\r\n  return (\r\n    <ol className={className ? `${listClass} ${className}` : listClass} {...props}>\r\n      {steps.map((step) => {\r\n        const status = step.status ?? \"pending\";\r\n        return (\r\n          <li key={step.id} className={stepClass} data-status={status}>\r\n            <span className={markerClass} data-status={status} aria-hidden=\"true\">\r\n              {status === \"running\" ? (\r\n                <span className={spinnerClass} />\r\n              ) : status === \"success\" ? (\r\n                <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\r\n                  <path\r\n                    d=\"M2.5 6.5L4.75 8.75L9.5 3.5\"\r\n                    stroke={theme.color.successForeground}\r\n                    strokeWidth=\"2\"\r\n                    strokeLinecap=\"round\"\r\n                    strokeLinejoin=\"round\"\r\n                  />\r\n                </svg>\r\n              ) : status === \"error\" ? (\r\n                <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\r\n                  <path\r\n                    d=\"M3.5 3.5L8.5 8.5M8.5 3.5L3.5 8.5\"\r\n                    stroke={theme.color.destructiveForeground}\r\n                    strokeWidth=\"2\"\r\n                    strokeLinecap=\"round\"\r\n                  />\r\n                </svg>\r\n              ) : (\r\n                <span className={dotClass} />\r\n              )}\r\n            </span>\r\n            <div className={bodyClass}>\r\n              <div className={headerRowClass}>\r\n                <p className={titleClass}>{step.title}</p>\r\n                {step.meta ? <span className={metaClass}>{step.meta}</span> : null}\r\n                <span\r\n                  style={{\r\n                    position: \"absolute\",\r\n                    width: 1,\r\n                    height: 1,\r\n                    overflow: \"hidden\",\r\n                    clip: \"rect(0,0,0,0)\",\r\n                    whiteSpace: \"nowrap\",\r\n                  }}\r\n                >\r\n                  {status}\r\n                </span>\r\n              </div>\r\n              {step.detail ? <div className={detailClass}>{step.detail}</div> : null}\r\n            </div>\r\n          </li>\r\n        );\r\n      })}\r\n    </ol>\r\n  );\r\n}\r\n",
      "type": "registry:component"
    }
  ]
}