{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "claude-code-message",
  "title": "Claude Code Message",
  "description": "User turns on a full-width bar and assistant turns behind a white bullet, with inline code and bold.",
  "dependencies": [
    "cn"
  ],
  "registryDependencies": [
    "card",
    "collapsible"
  ],
  "files": [
    {
      "path": "registry/notra/claude-code/components/claude-code-message.tsx",
      "content": "import { cn } from \"cn\";\n\nimport { renderClaudeCodeChildren } from \"../lib/claude-code-inline\";\nimport type { ClaudeCodeMessageProps } from \"../types/claude-code\";\n\nexport const ClaudeCodeMessage = ({\n  children,\n  className,\n  from = \"assistant\",\n  ...props\n}: ClaudeCodeMessageProps) => {\n  const isUser = from === \"user\";\n\n  return (\n    <div\n      className={cn(\n        \"font-claude-code grid min-w-0 grid-cols-[2ch_minmax(0,1fr)] text-[0.8125rem] leading-5\",\n        isUser\n          ? \"bg-claude-code-user-bg text-claude-code-strong\"\n          : \"text-claude-code-fg\",\n        className\n      )}\n      data-from={from}\n      data-slot=\"claude-code-message\"\n      {...props}\n    >\n      <span\n        aria-hidden=\"true\"\n        className={cn(\n          \"select-none\",\n          isUser ? \"text-claude-code-user-prompt\" : \"text-claude-code-strong\"\n        )}\n      >\n        {isUser ? \"❯\" : \"●\"}\n      </span>\n      <div className=\"min-w-0 break-words whitespace-pre-wrap\">\n        {renderClaudeCodeChildren(children)}\n      </div>\n    </div>\n  );\n};\n",
      "type": "registry:component",
      "target": "components/claude-code/components/claude-code-message.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/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"
}