{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"channel-message","type":"registry:component","title":"ChannelMessageBubble","description":"Canonical message bubble for any channel_messages record.","files":[{"path":"registry/default/ekairos/channel/channel-message.tsx","type":"registry:component","content":"\"use client\";\n\nimport type { ChannelMessage } from \"@ekairos/channel\";\nimport { cn } from \"@/lib/utils\";\nimport { ChannelBadge } from \"@/components/ekairos/channel/channel-badge\";\n\nexport type ChannelMessageBubbleProps = {\n  message: ChannelMessage;\n  className?: string;\n  /** Hide the channel badge (e.g. in single-channel views). */\n  hideChannel?: boolean;\n};\n\nfunction formatTime(value: string | undefined): string {\n  if (!value) return \"\";\n  try {\n    return new Intl.DateTimeFormat(undefined, {\n      hour: \"2-digit\",\n      minute: \"2-digit\",\n    }).format(new Date(value));\n  } catch {\n    return \"\";\n  }\n}\n\nfunction messageText(message: ChannelMessage): string {\n  if (message.text) return message.text;\n  const parts = Array.isArray(message.parts) ? message.parts : [];\n  return parts\n    .map((part) =>\n      part && typeof part === \"object\" && (part as { type?: unknown }).type === \"text\"\n        ? String((part as { text?: unknown }).text ?? \"\")\n        : \"\",\n    )\n    .filter(Boolean)\n    .join(\"\\n\");\n}\n\n/**\n * Canonical message bubble for any channel_messages record: direction decides\n * the side, role decides the tone, the badge tells the platform. Works for\n * every channel because it renders the canonical model — not provider\n * payloads.\n */\nexport function ChannelMessageBubble({ message, className, hideChannel }: ChannelMessageBubbleProps) {\n  const outbound = message.direction === \"outbound\";\n  const author =\n    message.participant ??\n    (message.role === \"assistant\" ? \"agent\" : message.role ?? message.direction);\n\n  return (\n    <article className={cn(\"flex\", outbound ? \"justify-end\" : \"justify-start\", className)}>\n      <div\n        className={cn(\n          \"max-w-[44rem] border px-4 py-3 text-sm leading-6\",\n          outbound\n            ? \"border-foreground/15 bg-foreground text-background\"\n            : \"border-border bg-muted/40 text-foreground\",\n        )}\n      >\n        <div\n          className={cn(\n            \"mb-1.5 flex flex-wrap items-center gap-2 text-[10px] uppercase tracking-[0.14em]\",\n            outbound ? \"text-background/60\" : \"text-muted-foreground\",\n          )}\n        >\n          <span className=\"font-mono\">{author}</span>\n          {!hideChannel ? (\n            <ChannelBadge\n              channel={message.channel}\n              className={outbound ? \"border-background/30 text-background/70\" : undefined}\n            />\n          ) : null}\n          {message.status ? <span className=\"font-mono opacity-70\">{message.status}</span> : null}\n          <span className=\"font-mono opacity-70\">{formatTime(message.createdAt)}</span>\n        </div>\n        <p className=\"m-0 whitespace-pre-wrap break-words\">{messageText(message)}</p>\n      </div>\n    </article>\n  );\n}\n","target":"components/ekairos/channel/channel-message.tsx"}],"dependencies":["@ekairos/channel@beta"],"devDependencies":[],"registryDependencies":["https://registry.ekairos.dev/r/channel-badge.json"]}