{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "claude-code-header",
  "title": "Claude Code Header",
  "description": "Claude Code's compact header: the pixel mascot next to version, model and working directory, with notices below.",
  "dependencies": [
    "cn"
  ],
  "registryDependencies": [
    "card",
    "collapsible"
  ],
  "files": [
    {
      "path": "registry/notra/claude-code/components/claude-code-header.tsx",
      "content": "import { cn } from \"cn\";\n\nimport { CLAUDE_CODE_RESULT_GLYPH } from \"../constants/claude-code\";\nimport { renderClaudeCodeInline } from \"../lib/claude-code-inline\";\nimport type { ClaudeCodeHeaderProps } from \"../types/claude-code\";\nimport { ClaudeCodeLogo } from \"./claude-code-logo\";\n\nexport const ClaudeCodeHeader = ({\n  className,\n  cwd = \"~/\",\n  model,\n  org,\n  tips = [],\n  version = \"v2.1.0\",\n  whatsNew = [],\n  ...props\n}: ClaudeCodeHeaderProps) => {\n  const plan = [model, org].filter(Boolean).join(\" · \");\n  const hasNotices = whatsNew.length > 0 || tips.length > 0;\n\n  return (\n    <div\n      className={cn(\n        \"font-claude-code text-claude-code-fg flex min-w-0 flex-col gap-5 text-[0.8125rem] leading-5\",\n        className\n      )}\n      data-slot=\"claude-code-header\"\n      {...props}\n    >\n      <div className=\"flex min-w-0 items-center gap-[2ch]\">\n        <ClaudeCodeLogo className=\"text-claude-code-accent shrink-0\" />\n        <div className=\"flex min-w-0 flex-col\">\n          <p className=\"truncate\">\n            <span className=\"text-claude-code-strong font-bold\">\n              Claude Code\n            </span>{\" \"}\n            <span className=\"text-claude-code-muted\">{version}</span>\n          </p>\n          {plan && <p className=\"text-claude-code-muted truncate\">{plan}</p>}\n          {cwd && <p className=\"text-claude-code-muted truncate\">{cwd}</p>}\n        </div>\n      </div>\n      {hasNotices && (\n        <div className=\"flex min-w-0 flex-col pl-[2ch]\">\n          {whatsNew.map((line) => (\n            <p key={line}>{renderClaudeCodeInline(line)}</p>\n          ))}\n          {tips.map((line) => (\n            <p className=\"text-claude-code-muted flex gap-[2ch]\" key={line}>\n              <span aria-hidden=\"true\" className=\"shrink-0\">\n                {CLAUDE_CODE_RESULT_GLYPH}\n              </span>\n              <span className=\"min-w-0\">{renderClaudeCodeInline(line)}</span>\n            </p>\n          ))}\n        </div>\n      )}\n    </div>\n  );\n};\n",
      "type": "registry:component",
      "target": "components/claude-code/components/claude-code-header.tsx"
    },
    {
      "path": "registry/notra/claude-code/components/claude-code-logo.tsx",
      "content": "import { useId } from \"react\";\n\nimport {\n  CLAUDE_CODE_MASCOT_BODY,\n  CLAUDE_CODE_MASCOT_EYES,\n  CLAUDE_CODE_MASCOT_SIZE,\n} from \"../constants/claude-code\";\nimport type { ClaudeCodeLogoProps } from \"../types/claude-code\";\n\nconst { height, width } = CLAUDE_CODE_MASCOT_SIZE;\n\nexport const ClaudeCodeLogo = ({\n  size = 76,\n  ...props\n}: ClaudeCodeLogoProps) => {\n  const maskId = useId();\n\n  return (\n    <svg\n      aria-hidden=\"true\"\n      fill=\"currentColor\"\n      height={(size * height) / width}\n      shapeRendering=\"crispEdges\"\n      viewBox={`0 0 ${width} ${height}`}\n      width={size}\n      xmlns=\"http://www.w3.org/2000/svg\"\n      {...props}\n    >\n      <mask id={maskId}>\n        {CLAUDE_CODE_MASCOT_BODY.map(([x, y, w, h]) => (\n          <rect\n            fill=\"white\"\n            height={h}\n            key={`${x}-${y}`}\n            width={w}\n            x={x}\n            y={y}\n          />\n        ))}\n        {CLAUDE_CODE_MASCOT_EYES.map(([x, y, w, h]) => (\n          <rect\n            fill=\"black\"\n            height={h}\n            key={`${x}-${y}`}\n            width={w}\n            x={x}\n            y={y}\n          />\n        ))}\n      </mask>\n      <rect height={height} mask={`url(#${maskId})`} width={width} />\n    </svg>\n  );\n};\n",
      "type": "registry:component",
      "target": "components/claude-code/components/claude-code-logo.tsx"
    },
    {
      "path": "registry/notra/claude-code/types/claude-code.ts",
      "content": "import type {\n  ChangeEventHandler,\n  ComponentProps,\n  KeyboardEventHandler,\n  ReactNode,\n  Ref,\n} from \"react\";\n\nimport type { Card } from \"@/components/ui/card\";\nimport type { Collapsible } from \"@/components/ui/collapsible\";\n\nexport type ClaudeCodeMode =\n  | \"auto\"\n  | \"manual\"\n  | \"accept-edits\"\n  | \"plan\"\n  | \"bypass\";\n\nexport type ClaudeCodeEffort =\n  | \"low\"\n  | \"medium\"\n  | \"high\"\n  | \"xhigh\"\n  | \"max\"\n  | \"ultracode\";\n\nexport type ClaudeCodeTodoStatus = \"done\" | \"active\" | \"todo\";\n\nexport type ClaudeCodeToolCallStatus = \"success\" | \"error\" | \"pending\";\n\nexport interface ClaudeCodeModeConfig {\n  className: string;\n  /** Whether the status line shows the shift+tab hint. */\n  cycles: boolean;\n  label: string;\n}\n\nexport interface ClaudeCodeEffortConfig {\n  className: string;\n  glyph: string;\n}\n\nexport interface ClaudeCodeTodoConfig {\n  glyph: string;\n  labelClassName: string;\n  srLabel: string;\n}\n\nexport interface ClaudeCodeToolCallConfig {\n  className: string;\n  srLabel: string;\n}\n\nexport interface ClaudeCodeTodo {\n  label: string;\n  status: ClaudeCodeTodoStatus;\n}\n\nexport interface ClaudeCodePullRequest {\n  href?: string;\n  number: number;\n}\n\nexport interface ClaudeCodeTerminalProps extends Omit<\n  ComponentProps<typeof Card>,\n  \"title\"\n> {\n  contentClassName?: string;\n  /** Pinned under the scrolling transcript, like Claude Code's prompt. */\n  footer?: ReactNode;\n  title?: ReactNode;\n}\n\nexport interface ClaudeCodeLogoProps extends ComponentProps<\"svg\"> {\n  size?: number;\n}\n\nexport interface ClaudeCodeHeaderProps extends ComponentProps<\"div\"> {\n  cwd?: string;\n  model?: string;\n  org?: string;\n  /** Dim `⎿` lines under the notices, like hook output or tips. */\n  tips?: string[];\n  version?: string;\n  /** Notice lines printed under the header. Supports `code` and **bold**. */\n  whatsNew?: string[];\n}\n\nexport interface ClaudeCodeMessageProps extends ComponentProps<\"div\"> {\n  from?: \"user\" | \"assistant\";\n}\n\nexport interface ClaudeCodeThinkingProps extends Omit<\n  ComponentProps<typeof Collapsible>,\n  \"children\"\n> {\n  children?: ReactNode;\n  label?: ReactNode;\n}\n\nexport interface ClaudeCodeSpinnerProps extends ComponentProps<\"div\"> {\n  /** Extra fields in the parentheses, like `thinking`. */\n  details?: string[];\n  elapsed?: string;\n  /** Freeze the glyph, for screenshots and reduced motion. */\n  paused?: boolean;\n  tip?: string;\n  tokens?: number;\n  verb?: string;\n}\n\nexport interface ClaudeCodeTurnSummaryProps extends ComponentProps<\"div\"> {\n  doneAt?: string;\n  duration: string;\n  verb?: string;\n}\n\nexport interface ClaudeCodeInterruptedProps extends ComponentProps<\"p\"> {\n  /** Shown after `Interrupted ·`. */\n  hint?: ReactNode;\n}\n\nexport interface ClaudeCodeTodoListProps extends ComponentProps<\"div\"> {\n  /** The tool line above the list. Pass `null` to leave it out. */\n  heading?: string | null;\n  todos: ClaudeCodeTodo[];\n}\n\nexport interface ClaudeCodeToolCallProps extends Omit<\n  ComponentProps<typeof Collapsible>,\n  \"children\"\n> {\n  arg?: string;\n  children?: ReactNode;\n  result: ReactNode;\n  status?: ClaudeCodeToolCallStatus;\n  tool: string;\n}\n\nexport interface ClaudeCodeToolSummaryProps extends Omit<\n  ComponentProps<typeof Collapsible>,\n  \"children\"\n> {\n  children?: ReactNode;\n  count: number;\n  noun?: string;\n  verb?: string;\n}\n\nexport interface ClaudeCodePromptProps extends Omit<\n  ComponentProps<\"form\">,\n  \"defaultValue\" | \"onChange\" | \"onKeyDown\" | \"onSubmit\"\n> {\n  /** A turn is running: Enter does not send and Escape calls `onStop`. */\n  busy?: boolean;\n  defaultValue?: string;\n  effort?: ClaudeCodeEffort | false;\n  inputClassName?: string;\n  inputRef?: Ref<HTMLInputElement>;\n  mode?: ClaudeCodeMode;\n  onChange?: ChangeEventHandler<HTMLInputElement>;\n  onKeyDown?: KeyboardEventHandler<HTMLInputElement>;\n  /**\n   * Called with the trimmed text on Enter. An uncontrolled prompt clears\n   * afterwards; with `value`, clear it yourself here.\n   */\n  onSend?: (text: string) => void;\n  /** Called on Escape while `busy`, to interrupt the running turn. */\n  onStop?: () => void;\n  placeholder?: string;\n  pullRequest?: ClaudeCodePullRequest;\n  value?: string;\n}\n\nexport interface ClaudeCodeSessionHeader {\n  cwd: string;\n  model: string;\n  org: string;\n  tips: string[];\n  version: string;\n  whatsNew: string[];\n}\n\nexport interface ClaudeCodeSessionToolCall {\n  arg?: string;\n  detail?: string;\n  id: string;\n  result: string;\n  status?: ClaudeCodeToolCallStatus;\n  tool: string;\n}\n\nexport interface ClaudeCodeSessionSpinner {\n  details: string[];\n  elapsed: string;\n  tip: string;\n  tokens: number;\n  verb: string;\n}\n\nexport interface ClaudeCodeSessionTurn {\n  answer: string;\n  commands: ClaudeCodeSessionToolCall[];\n  id: string;\n  prompt: string;\n  summary: ClaudeCodeSessionSummary;\n  thinking?: string;\n  todos?: ClaudeCodeTodo[];\n}\n\nexport interface ClaudeCodeSessionSummary {\n  doneAt: string;\n  duration: string;\n  verb: string;\n}\n\nexport type ClaudeCodeTurnStatus =\n  | \"working\"\n  | \"streaming\"\n  | \"done\"\n  | \"interrupted\";\n\n/** A scripted answer the demo plays back when you send a prompt. */\nexport interface ClaudeCodeReply {\n  answer: string;\n  commands: ClaudeCodeSessionToolCall[];\n  /** The spinner verb while the turn runs, like `Sketching`. */\n  spinnerVerb: string;\n  /** The verb on the summary line once the turn is done, like `Cooked`. */\n  summaryVerb: string;\n}\n\nexport interface ClaudeCodeChatTurn extends Omit<\n  ClaudeCodeSessionTurn,\n  \"summary\"\n> {\n  status: ClaudeCodeTurnStatus;\n  summary?: ClaudeCodeSessionSummary;\n}\n\nexport interface ClaudeCodeChat {\n  busy: boolean;\n  /** Whole seconds since the running turn started. */\n  elapsed: number;\n  send: (text: string) => Promise<void>;\n  spinnerVerb: string;\n  stop: () => void;\n  /** Tokens streamed in the running turn so far. */\n  tokens: number;\n  turns: ClaudeCodeChatTurn[];\n}\n\nexport interface ClaudeCodeSessionPendingTurn {\n  prompt: string;\n  spinner: ClaudeCodeSessionSpinner;\n  todos: ClaudeCodeTodo[];\n  toolCall: ClaudeCodeSessionToolCall;\n}\n\nexport interface ClaudeCodeSession {\n  header: ClaudeCodeSessionHeader;\n  pending: ClaudeCodeSessionPendingTurn;\n  promptPlaceholder: string;\n  pullRequest: ClaudeCodePullRequest;\n  title: string;\n  turns: ClaudeCodeSessionTurn[];\n}\n",
      "type": "registry:lib",
      "target": "components/claude-code/types/claude-code.ts"
    },
    {
      "path": "registry/notra/claude-code/constants/claude-code.ts",
      "content": "import type {\n  ClaudeCodeEffort,\n  ClaudeCodeEffortConfig,\n  ClaudeCodeMode,\n  ClaudeCodeModeConfig,\n  ClaudeCodeTodoConfig,\n  ClaudeCodeTodoStatus,\n  ClaudeCodeToolCallConfig,\n  ClaudeCodeToolCallStatus,\n} from \"../types/claude-code\";\n\nexport const CLAUDE_CODE_MODE_ORDER: ClaudeCodeMode[] = [\n  \"manual\",\n  \"accept-edits\",\n  \"plan\",\n  \"auto\",\n  \"bypass\",\n];\n\nexport const CLAUDE_CODE_EFFORT_ORDER: ClaudeCodeEffort[] = [\n  \"low\",\n  \"medium\",\n  \"high\",\n  \"xhigh\",\n  \"max\",\n  \"ultracode\",\n];\n\nexport const CLAUDE_CODE_MODES: Record<ClaudeCodeMode, ClaudeCodeModeConfig> = {\n  \"accept-edits\": {\n    className: \"text-claude-code-mode-accept-edits\",\n    cycles: true,\n    label: \"⏵⏵ accept edits on\",\n  },\n  auto: {\n    className: \"text-claude-code-mode-auto\",\n    cycles: true,\n    label: \"⏵⏵ auto mode on\",\n  },\n  bypass: {\n    className: \"text-claude-code-mode-bypass\",\n    cycles: true,\n    label: \"⏵⏵ bypass permissions on\",\n  },\n  manual: {\n    className: \"text-claude-code-muted\",\n    cycles: false,\n    label: \"? for shortcuts\",\n  },\n  plan: {\n    className: \"text-claude-code-mode-plan\",\n    cycles: true,\n    label: \"⏸ plan mode on\",\n  },\n};\n\nexport const CLAUDE_CODE_EFFORTS: Record<\n  ClaudeCodeEffort,\n  ClaudeCodeEffortConfig\n> = {\n  high: { className: \"text-claude-code-muted\", glyph: \"◕\" },\n  low: { className: \"text-claude-code-muted\", glyph: \"○\" },\n  max: { className: \"text-claude-code-muted\", glyph: \"●\" },\n  medium: { className: \"text-claude-code-muted\", glyph: \"◑\" },\n  ultracode: { className: \"text-claude-code-accent\", glyph: \"✦\" },\n  xhigh: { className: \"text-claude-code-muted\", glyph: \"◉\" },\n};\n\nexport const CLAUDE_CODE_TODOS: Record<\n  ClaudeCodeTodoStatus,\n  ClaudeCodeTodoConfig\n> = {\n  active: {\n    glyph: \"☐\",\n    labelClassName: \"text-claude-code-strong font-bold\",\n    srLabel: \"In progress\",\n  },\n  done: {\n    glyph: \"☒\",\n    labelClassName: \"text-claude-code-muted line-through\",\n    srLabel: \"Done\",\n  },\n  todo: {\n    glyph: \"☐\",\n    labelClassName: \"text-claude-code-fg\",\n    srLabel: \"To do\",\n  },\n};\n\nexport const CLAUDE_CODE_TOOL_CALLS: Record<\n  ClaudeCodeToolCallStatus,\n  ClaudeCodeToolCallConfig\n> = {\n  error: { className: \"text-claude-code-error\", srLabel: \"Failed\" },\n  pending: {\n    className:\n      \"text-claude-code-muted animate-pulse motion-reduce:animate-none\",\n    srLabel: \"Running\",\n  },\n  success: { className: \"text-claude-code-success\", srLabel: \"Done\" },\n};\n\nexport const CLAUDE_CODE_SPINNER_FRAMES = [\"·\", \"✢\", \"✳\", \"✶\", \"✻\", \"✽\"];\n\nexport const CLAUDE_CODE_SPINNER_INTERVAL_MS = 120;\n\nexport const CLAUDE_CODE_RESULT_GLYPH = \"⎿\";\n\nexport const CLAUDE_CODE_CHAT_TIMING = {\n  thinkMs: 1200,\n  toolMs: 900,\n  wordMs: 28,\n  reducedMaxMs: 60,\n  tickMs: 1000,\n} as const;\n\nexport const CLAUDE_CODE_MASCOT_SIZE = { height: 14, width: 22 };\n\nexport const CLAUDE_CODE_MASCOT_BODY: [number, number, number, number][] = [\n  [2, 0, 18, 10],\n  [0, 4, 22, 3],\n  [3, 10, 2, 4],\n  [7, 10, 2, 4],\n  [13, 10, 2, 4],\n  [17, 10, 2, 4],\n];\n\nexport const CLAUDE_CODE_MASCOT_EYES: [number, number, number, number][] = [\n  [6, 2, 2, 3],\n  [14, 2, 2, 3],\n];\n",
      "type": "registry:lib",
      "target": "components/claude-code/constants/claude-code.ts"
    },
    {
      "path": "registry/notra/claude-code/lib/claude-code-inline.tsx",
      "content": "import type { ReactNode } from \"react\";\n\nconst INLINE_TOKEN = /(`[^`]+`|\\*\\*[^*]+\\*\\*)/g;\n\nexport const renderClaudeCodeInline = (text: string): ReactNode[] => {\n  let offset = 0;\n\n  return text.split(INLINE_TOKEN).map((part) => {\n    const key = `${offset}-${part}`;\n    offset += part.length;\n\n    if (part.length > 2 && part.startsWith(\"`\") && part.endsWith(\"`\")) {\n      return (\n        <code className=\"text-claude-code-link font-claude-code\" key={key}>\n          {part.slice(1, -1)}\n        </code>\n      );\n    }\n\n    if (part.length > 4 && part.startsWith(\"**\") && part.endsWith(\"**\")) {\n      return (\n        <strong className=\"text-claude-code-strong font-bold\" key={key}>\n          {part.slice(2, -2)}\n        </strong>\n      );\n    }\n\n    return part;\n  });\n};\n\nexport const renderClaudeCodeChildren = (children: ReactNode): ReactNode =>\n  typeof children === \"string\" ? renderClaudeCodeInline(children) : children;\n",
      "type": "registry:lib",
      "target": "components/claude-code/lib/claude-code-inline.tsx"
    }
  ],
  "cssVars": {
    "theme": {
      "color-claude-code-bg": "var(--claude-code-bg)",
      "color-claude-code-chrome": "var(--claude-code-chrome)",
      "color-claude-code-traffic": "var(--claude-code-traffic)",
      "color-claude-code-title": "var(--claude-code-title)",
      "color-claude-code-shadow": "var(--claude-code-shadow)",
      "color-claude-code-ring": "var(--claude-code-ring)",
      "color-claude-code-fg": "var(--claude-code-fg)",
      "color-claude-code-strong": "var(--claude-code-strong)",
      "color-claude-code-accent": "var(--claude-code-accent)",
      "color-claude-code-muted": "var(--claude-code-muted)",
      "color-claude-code-rule": "var(--claude-code-rule)",
      "color-claude-code-link": "var(--claude-code-link)",
      "color-claude-code-pr": "var(--claude-code-pr)",
      "color-claude-code-user-bg": "var(--claude-code-user-bg)",
      "color-claude-code-user-prompt": "var(--claude-code-user-prompt)",
      "color-claude-code-success": "var(--claude-code-success)",
      "color-claude-code-error": "var(--claude-code-error)",
      "color-claude-code-mode-auto": "var(--claude-code-mode-auto)",
      "color-claude-code-mode-accept-edits": "var(--claude-code-mode-accept-edits)",
      "color-claude-code-mode-plan": "var(--claude-code-mode-plan)",
      "color-claude-code-mode-bypass": "var(--claude-code-mode-bypass)",
      "font-claude-code": "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace"
    },
    "light": {
      "claude-code-bg": "#ffffff",
      "claude-code-chrome": "#ececec",
      "claude-code-traffic": "#d4d4d4",
      "claude-code-title": "#00000073",
      "claude-code-shadow": "#00000026",
      "claude-code-ring": "#0000001a",
      "claude-code-fg": "#1f1f1f",
      "claude-code-strong": "#000000",
      "claude-code-accent": "#d77757",
      "claude-code-muted": "#666666",
      "claude-code-rule": "#999999",
      "claude-code-link": "#5769f7",
      "claude-code-pr": "#966c1e",
      "claude-code-user-bg": "#f0f0f0",
      "claude-code-user-prompt": "#999999",
      "claude-code-success": "#2c7a39",
      "claude-code-error": "#ab2b3f",
      "claude-code-mode-auto": "#966c1e",
      "claude-code-mode-accept-edits": "#8700ff",
      "claude-code-mode-plan": "#006666",
      "claude-code-mode-bypass": "#d1245a"
    },
    "dark": {
      "claude-code-bg": "#0f0f0f",
      "claude-code-chrome": "#1c1c1c",
      "claude-code-traffic": "#3a3a3a",
      "claude-code-title": "#ffffff66",
      "claude-code-shadow": "#0000004d",
      "claude-code-ring": "#ffffff1a",
      "claude-code-fg": "#f7f7f7",
      "claude-code-strong": "#ffffff",
      "claude-code-accent": "#e06443",
      "claude-code-muted": "#8c8c8c",
      "claude-code-rule": "#7b7b7b",
      "claude-code-link": "#a4b0fc",
      "claude-code-pr": "#d9b559",
      "claude-code-user-bg": "#2e2e2e",
      "claude-code-user-prompt": "#5c5c5c",
      "claude-code-success": "#4eba65",
      "claude-code-error": "#ff6b80",
      "claude-code-mode-auto": "#e5c07b",
      "claude-code-mode-accept-edits": "#af87ff",
      "claude-code-mode-plan": "#48968c",
      "claude-code-mode-bypass": "#fd526f"
    }
  },
  "type": "registry:component"
}