export declare const WEB_APP_TEMPLATE_FILES: {
    readonly "agent/channels/eve.ts": 'import { eveChannel } from "eve/channels/eve";\nimport { localDev, placeholderAuth, vercelOidc } from "eve/channels/auth";\n\nexport default eveChannel({\n  auth: [\n    // Lets the eve TUI and your Vercel deployments reach the deployed agent.\n    vercelOidc(),\n    // Open on localhost for `eve dev` and the REPL; ignored in production.\n    localDev(),\n    // This placeholder will not allow browser requests in production.\n    // Replace it with your app\'s auth provider, like Auth.js or Clerk,\n    // or use none() for a public demo.\n    placeholderAuth(),\n  ],\n});\n';
    readonly "app/_components/agent-chat.tsx": '"use client";\n\nimport type { UserContent } from "ai";\nimport { useEveAgent } from "eve/react";\nimport { AlertCircleIcon, BrainIcon, PlusIcon, SquareIcon } from "lucide-react";\nimport { useState } from "react";\nimport {\n  Conversation,\n  ConversationContent,\n  ConversationScrollButton,\n  ConversationTopFade,\n} from "@/components/ai-elements/conversation";\nimport { Message, MessageContent } from "@/components/ai-elements/message";\nimport {\n  PromptInput,\n  PromptInputButton,\n  type PromptInputMessage,\n  PromptInputSubmit,\n  PromptInputTextarea,\n  usePromptInputAttachments,\n} from "@/components/ai-elements/prompt-input";\nimport { Shimmer } from "@/components/ai-elements/shimmer";\nimport { Button } from "@/components/ui/button";\nimport { cn } from "@/lib/utils";\nimport { AgentMessage } from "./agent-message";\n\nconst AGENT_NAME = "__EVE_INIT_APP_NAME__";\n\nexport function AgentChat({\n  sessionId,\n  sessionless = false,\n}: {\n  readonly sessionId?: string;\n  readonly sessionless?: boolean;\n}) {\n  const [cancellationError, setCancellationError] = useState<string>();\n  const [hasInputText, setHasInputText] = useState(false);\n  const agent = useEveAgent({\n    initialSession:\n      sessionId === undefined\n        ? undefined\n        : {\n            sessionId,\n            streamIndex: 0,\n          },\n    resume: sessionId !== undefined,\n    onSessionChange(session) {\n      if (sessionId === undefined && session !== undefined) {\n        // Next patches window.history to navigate, which would detach the active stream.\n        History.prototype.replaceState.call(\n          window.history,\n          window.history.state,\n          "",\n          `/s/${encodeURIComponent(session.sessionId)}`,\n        );\n      }\n    },\n  });\n\n  const isBusy = agent.status === "submitted" || agent.status === "streaming";\n  const isResuming = agent.status === "resuming";\n  const isEmpty = agent.data.messages.length === 0;\n  const lastMessage = agent.data.messages.at(-1);\n  const isPendingAssistantShell =\n    lastMessage?.role === "assistant" &&\n    lastMessage.parts.every((part) => part.type === "step-start");\n  const showPendingThinking =\n    isBusy &&\n    (agent.status === "submitted" || lastMessage?.role !== "assistant" || isPendingAssistantShell);\n  const turnFailure = isBusy || isResuming ? undefined : getLatestTurnFailure(agent.events);\n  const errorMessage = cancellationError ?? agent.error?.message ?? turnFailure;\n  const hasConversationContent = sessionless || !isEmpty || errorMessage !== undefined;\n  const showConversationLayout = isResuming || hasConversationContent;\n  const activeSessionId = sessionId ?? agent.session?.sessionId;\n\n  const requestCancellation = () => {\n    setCancellationError(undefined);\n    void agent.cancel().catch((error: unknown) => {\n      setCancellationError(toErrorMessage(error));\n    });\n  };\n\n  const handleSubmit = async (message: PromptInputMessage) => {\n    const text = message.text.trim();\n    if ((text.length === 0 && message.files.length === 0) || isResuming) return;\n\n    setHasInputText(false);\n    setCancellationError(undefined);\n    const options = isBusy ? { turnPolicy: "steer" as const } : undefined;\n\n    if (message.files.length === 0) {\n      await agent.send(text, options);\n      return;\n    }\n\n    const parts: UserContent = [];\n    if (text.length > 0) {\n      parts.push({ text, type: "text" });\n    }\n    for (const file of message.files) {\n      parts.push({\n        data: file.url,\n        filename: file.filename,\n        mediaType: file.mediaType,\n        type: "file",\n      });\n    }\n\n    await agent.send(parts, options);\n  };\n\n  const composer = (\n    <PromptInput onSubmit={handleSubmit}>\n      <PromptInputTextarea\n        disabled={isResuming}\n        onChange={(event) => setHasInputText(event.currentTarget.value.trim().length > 0)}\n        placeholder="Send a message…"\n      />\n      <ComposerAction\n        hasInputText={hasInputText}\n        isBusy={isBusy}\n        isResuming={isResuming}\n        onCancel={requestCancellation}\n      />\n    </PromptInput>\n  );\n\n  return (\n    <main className="flex h-dvh flex-col overflow-hidden bg-background text-foreground">\n      {showConversationLayout ? (\n        <ChatHeader canStartNewChat={activeSessionId !== undefined} />\n      ) : null}\n\n      {showConversationLayout ? (\n        <Conversation\n          className="min-h-0 flex-1"\n          initial={sessionId === undefined ? undefined : false}\n          resize={activeSessionId === undefined ? "smooth" : "instant"}\n          scrollRestorationKey={\n            isEmpty || activeSessionId === undefined\n              ? undefined\n              : `eve:web-chat-scroll:${activeSessionId}`\n          }\n        >\n          <ConversationTopFade className="top-14" />\n          <ConversationContent className="mx-auto w-full max-w-3xl gap-6 px-4 pt-20 pb-36 sm:px-6">\n            {agent.data.messages.map((message, index) =>\n              showPendingThinking &&\n              isPendingAssistantShell &&\n              message.id === lastMessage.id ? null : (\n                <AgentMessage\n                  canRespond={!isBusy && !isResuming}\n                  isStreaming={\n                    agent.status === "streaming" && index === agent.data.messages.length - 1\n                  }\n                  key={message.id}\n                  message={message}\n                  onInputResponses={(inputResponses) => {\n                    setCancellationError(undefined);\n                    return agent.respond(inputResponses);\n                  }}\n                />\n              ),\n            )}\n            {showPendingThinking ? <PendingThinking /> : null}\n            {errorMessage ? <ErrorMessage message={errorMessage} /> : null}\n          </ConversationContent>\n          <ConversationScrollButton />\n        </Conversation>\n      ) : null}\n\n      <div\n        className={cn(\n          "mx-auto w-full px-4 sm:px-6",\n          showConversationLayout\n            ? "fixed bottom-0 left-1/2 z-20 max-w-3xl -translate-x-1/2 bg-gradient-to-t from-background via-background to-transparent pt-4 pb-6"\n            : "flex max-w-xl flex-1 flex-col items-center justify-center gap-8 pb-[10vh]",\n        )}\n      >\n        {showConversationLayout ? null : (\n          <div className="flex flex-col items-center gap-3 text-center">\n            <h1 className="font-medium text-5xl tracking-tighter">{AGENT_NAME}</h1>\n          </div>\n        )}\n        <div className="w-full">{composer}</div>\n      </div>\n    </main>\n  );\n}\n\nfunction ComposerAction({\n  hasInputText,\n  isBusy,\n  isResuming,\n  onCancel,\n}: {\n  readonly hasInputText: boolean;\n  readonly isBusy: boolean;\n  readonly isResuming: boolean;\n  readonly onCancel: () => void;\n}) {\n  const attachments = usePromptInputAttachments();\n  const canSubmit = hasInputText || attachments.files.length > 0;\n\n  if (!isBusy || canSubmit) {\n    return <PromptInputSubmit disabled={isResuming} />;\n  }\n\n  return (\n    <PromptInputButton\n      aria-label="Stop"\n      className="absolute right-2.5 bottom-2.5"\n      onClick={onCancel}\n      variant="outline"\n    >\n      <SquareIcon className="size-3 fill-current" />\n    </PromptInputButton>\n  );\n}\n\nfunction ErrorMessage({ message }: { readonly message: string }) {\n  return (\n    <Message className="max-w-full" from="assistant">\n      <MessageContent>\n        <div\n          className="flex w-full items-start gap-3 rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2.5 text-sm"\n          role="alert"\n        >\n          <AlertCircleIcon className="mt-0.5 size-4 shrink-0 text-destructive" />\n          <div>\n            <p className="font-medium">Request failed</p>\n            <p className="mt-0.5 text-muted-foreground">{message}</p>\n          </div>\n        </div>\n      </MessageContent>\n    </Message>\n  );\n}\n\nfunction ChatHeader({ canStartNewChat }: { readonly canStartNewChat: boolean }) {\n  return (\n    <header className="pointer-events-none fixed top-0 right-0 left-0 z-20 h-14">\n      <div className="relative mx-auto flex h-full w-full max-w-3xl items-center justify-center bg-background px-24">\n        <span className="truncate text-muted-foreground text-sm">{AGENT_NAME}</span>\n        {canStartNewChat ? (\n          <Button\n            aria-label="Start a new chat"\n            className="pointer-events-auto fixed top-3 right-6 pr-4"\n            onClick={() => window.location.assign("/s")}\n            size="sm"\n            type="button"\n            variant="ghost"\n          >\n            <PlusIcon className="size-4" />\n            <span className="hidden font-normal text-sm sm:inline">New chat</span>\n          </Button>\n        ) : null}\n      </div>\n    </header>\n  );\n}\n\nfunction PendingThinking() {\n  return (\n    <Message aria-live="polite" from="assistant">\n      <MessageContent>\n        <div className="mb-4 flex w-full items-center gap-2 text-muted-foreground text-sm">\n          <BrainIcon className="size-4" />\n          <Shimmer duration={1}>Thinking</Shimmer>\n        </div>\n      </MessageContent>\n    </Message>\n  );\n}\n\nfunction toErrorMessage(error: unknown): string {\n  return error instanceof Error ? error.message : "Unable to cancel the response.";\n}\n\nfunction getLatestTurnFailure(\n  events: ReturnType<typeof useEveAgent>["events"],\n): string | undefined {\n  for (let index = events.length - 1; index >= 0; index -= 1) {\n    const event = events[index];\n\n    if (event.type === "turn.failed") {\n      return event.data.code === "MODEL_CALL_FAILED"\n        ? "The model is temporarily unavailable. Please try again."\n        : event.data.message;\n    }\n\n    if (event.type === "turn.completed" || event.type === "turn.cancelled") {\n      return undefined;\n    }\n\n    if (event.type === "message.received") {\n      return undefined;\n    }\n  }\n\n  return undefined;\n}\n';
    readonly "app/_components/agent-message.tsx": '"use client";\n\nimport type {\n  EveAuthorizationPart,\n  EveDynamicToolPart,\n  EveMessage,\n  EveMessageInputRequest,\n  EveMessagePart,\n} from "eve/react";\nimport { useState } from "react";\nimport {\n  ArrowRightIcon,\n  CheckCircleIcon,\n  CheckIcon,\n  ExternalLinkIcon,\n  FileIcon,\n  ImageIcon,\n  KeyRoundIcon,\n  XCircleIcon,\n} from "lucide-react";\nimport { Message, MessageContent, MessageResponse } from "@/components/ai-elements/message";\nimport {\n  Question,\n  QuestionInput,\n  QuestionOption,\n  QuestionOptions,\n  QuestionPrompt,\n  type QuestionResponse,\n  QuestionSubmit,\n  type QuestionValue,\n} from "@/components/ai-elements/question";\nimport { Reasoning, ReasoningContent, ReasoningTrigger } from "@/components/ai-elements/reasoning";\nimport {\n  BashToolContent,\n  Tool,\n  ToolContent,\n  ToolHeader,\n  ToolInput,\n  ToolOutput,\n} from "@/components/ai-elements/tool";\nimport { Button } from "@/components/ui/button";\nimport { cn } from "@/lib/utils";\n\nexport type AgentInputResponse = {\n  readonly optionId?: string;\n  readonly requestId: string;\n  readonly text?: string;\n};\n\ntype EveFilePart = Extract<EveMessagePart, { type: "file" }>;\n\nexport function AgentMessage({\n  canRespond,\n  isStreaming,\n  message,\n  onInputResponses,\n}: {\n  readonly canRespond: boolean;\n  readonly isStreaming: boolean;\n  readonly message: EveMessage;\n  readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n}) {\n  const lastTextIndex = message.parts.reduce(\n    (last, part, index) => (part.type === "text" ? index : last),\n    -1,\n  );\n  const hasAssistantText =\n    message.role === "assistant" &&\n    message.parts.some((part) => part.type === "text" && part.text.length > 0);\n\n  return (\n    <Message\n      data-optimistic={message.metadata?.optimistic ? "true" : undefined}\n      from={message.role}\n    >\n      <MessageContent>\n        {message.parts.map((part, index) =>\n          hasAssistantText && part.type === "reasoning" ? null : (\n            <AgentMessagePart\n              canRespond={canRespond}\n              key={partKey(part, index)}\n              onInputResponses={onInputResponses}\n              part={part}\n              showCaret={isStreaming && message.role === "assistant" && index === lastTextIndex}\n            />\n          ),\n        )}\n      </MessageContent>\n    </Message>\n  );\n}\n\nfunction AgentMessagePart({\n  canRespond,\n  onInputResponses,\n  part,\n  showCaret,\n}: {\n  readonly canRespond: boolean;\n  readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n  readonly part: EveMessagePart;\n  readonly showCaret: boolean;\n}) {\n  switch (part.type) {\n    case "step-start":\n      return null;\n    case "text":\n      return (\n        <MessageResponse caret="block" isAnimating={showCaret}>\n          {part.text}\n        </MessageResponse>\n      );\n    case "reasoning":\n      return (\n        <Reasoning defaultOpen isStreaming={part.state === "streaming"}>\n          <ReasoningTrigger />\n          <ReasoningContent>{part.text}</ReasoningContent>\n        </Reasoning>\n      );\n    case "file":\n      return <AttachmentPart part={part} />;\n    case "authorization":\n      return <AuthorizationPrompt part={part} />;\n    case "dynamic-tool": {\n      const inputRequest = part.toolMetadata?.eve?.inputRequest;\n      if (inputRequest?.kind === "question") {\n        return (\n          <QuestionRequest\n            canRespond={canRespond}\n            inputRequest={inputRequest}\n            inputResponse={part.toolMetadata?.eve?.inputResponse}\n            onInputResponses={onInputResponses}\n          />\n        );\n      }\n\n      return (\n        <Tool\n          defaultOpen={part.state === "approval-requested" || part.state === "approval-responded"}\n        >\n          <ToolHeader\n            state={part.state}\n            title={part.toolName}\n            toolName={part.toolName}\n            type="dynamic-tool"\n          />\n          <ToolContent>\n            {part.toolName === "bash" ? (\n              <BashToolContent errorText={part.errorText} input={part.input} output={part.output} />\n            ) : (\n              <ToolInput input={part.input} />\n            )}\n            <InputRequestActions\n              canRespond={canRespond}\n              part={part}\n              onInputResponses={onInputResponses}\n            />\n            {part.toolName === "bash" ? null : (\n              <ToolOutput errorText={part.errorText} output={part.output} />\n            )}\n          </ToolContent>\n        </Tool>\n      );\n    }\n  }\n}\n\nfunction QuestionRequest({\n  canRespond,\n  inputRequest,\n  inputResponse,\n  onInputResponses,\n}: {\n  readonly canRespond: boolean;\n  readonly inputRequest: EveMessageInputRequest;\n  readonly inputResponse?: AgentInputResponse;\n  readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n}) {\n  const hasOptions = (inputRequest.options?.length ?? 0) > 0;\n  const acceptsFreeform = inputRequest.allowFreeform === true || !hasOptions;\n  const [questionValue, setQuestionValue] = useState<QuestionValue>({\n    selectedValues: inputResponse?.optionId ? [inputResponse.optionId] : [],\n    text: inputResponse?.text ?? "",\n  });\n\n  const submitOption = (optionId: string) => {\n    setQuestionValue((value) => ({ ...value, selectedValues: [optionId] }));\n    return onInputResponses([\n      {\n        optionId,\n        requestId: inputRequest.requestId,\n      },\n    ]);\n  };\n\n  const submitResponse = ({ selectedValues, text }: QuestionResponse) =>\n    onInputResponses([\n      {\n        optionId: selectedValues[0],\n        requestId: inputRequest.requestId,\n        text,\n      },\n    ]);\n\n  return (\n    <Question\n      disabled={!canRespond || inputResponse !== undefined}\n      onSubmit={submitResponse}\n      onValueChange={setQuestionValue}\n      value={questionValue}\n    >\n      <QuestionPrompt>{inputRequest.prompt}</QuestionPrompt>\n      {hasOptions ? (\n        <QuestionOptions className="flex-col items-stretch" aria-label={inputRequest.prompt}>\n          {inputRequest.options?.map((option, index) => (\n            <QuestionOption\n              className="justify-start px-3 py-2 text-left"\n              key={option.id}\n              onClick={() => void submitOption(option.id)}\n              value={option.id}\n            >\n              <span className="min-w-0 flex-1">\n                <span className="block text-foreground text-sm leading-tight">{option.label}</span>\n                {option.description ? (\n                  <span className="block text-sm text-muted-foreground leading-tight">\n                    {option.description}\n                  </span>\n                ) : null}\n              </span>\n              {inputResponse === undefined ? (\n                <span aria-hidden="true" className="relative size-6 shrink-0">\n                  <span className="absolute inset-0 flex items-center justify-center rounded-full bg-foreground/8 text-xs text-muted-foreground transition-opacity group-hover/option:opacity-0 group-focus-visible/option:opacity-0">\n                    {index + 1}\n                  </span>\n                  <ArrowRightIcon className="absolute top-1/2 left-1/2 size-4 -translate-x-1/2 -translate-y-1/2 text-muted-foreground opacity-0 transition-[color,opacity] group-hover/option:text-foreground group-hover/option:opacity-100 group-focus-visible/option:opacity-100" />\n                </span>\n              ) : (\n                <CheckIcon className="size-4 shrink-0 opacity-0 transition-opacity group-data-[state=checked]/option:opacity-100" />\n              )}\n            </QuestionOption>\n          ))}\n        </QuestionOptions>\n      ) : null}\n      {acceptsFreeform ? (\n        <div className="relative">\n          <QuestionInput\n            aria-label="Answer"\n            className={inputResponse === undefined ? "pr-12 pb-12" : undefined}\n            placeholder="Type your answer…"\n          />\n          {inputResponse === undefined && questionValue.text.trim().length > 0 ? (\n            <QuestionSubmit\n              aria-label="Answer"\n              className="absolute right-2 bottom-2"\n              size="icon-sm"\n            >\n              <ArrowRightIcon />\n            </QuestionSubmit>\n          ) : null}\n        </div>\n      ) : null}\n    </Question>\n  );\n}\n\nfunction AttachmentPart({ part }: { readonly part: EveFilePart }) {\n  const label = part.filename ?? "Attachment";\n  const detail = [part.mediaType, formatBytes(part.size)].filter(Boolean).join(" - ");\n  const isImage = part.mediaType.startsWith("image/") && part.url !== undefined;\n  const Icon = isImage ? ImageIcon : FileIcon;\n  const body = (\n    <span className="flex max-w-sm items-center gap-3 rounded-md border bg-background/60 p-2 text-sm">\n      {isImage ? (\n        <img alt={label} className="size-12 shrink-0 rounded-sm object-cover" src={part.url} />\n      ) : (\n        <span className="flex size-10 shrink-0 items-center justify-center rounded-sm bg-muted text-muted-foreground">\n          <Icon className="size-4" />\n        </span>\n      )}\n      <span className="min-w-0 flex-1">\n        <span className="block truncate font-medium">{label}</span>\n        {detail ? <span className="block truncate text-muted-foreground">{detail}</span> : null}\n      </span>\n      {part.url ? <ExternalLinkIcon className="size-4 shrink-0 text-muted-foreground" /> : null}\n    </span>\n  );\n\n  return part.url ? (\n    <a href={part.url} rel="noreferrer" target="_blank">\n      {body}\n    </a>\n  ) : (\n    body\n  );\n}\n\nfunction AuthorizationPrompt({ part }: { readonly part: EveAuthorizationPart }) {\n  const isAuthorized = part.state === "completed" && part.outcome === "authorized";\n  const isCompleted = part.state === "completed";\n  const Icon = isAuthorized ? CheckCircleIcon : isCompleted ? XCircleIcon : KeyRoundIcon;\n  const instructions = part.authorization?.instructions;\n  const shouldShowInstructions = instructions !== undefined && instructions !== part.description;\n\n  return (\n    <div\n      className={cn(\n        "space-y-3 rounded-md border p-3",\n        isAuthorized\n          ? "border-emerald-500/30 bg-emerald-500/5"\n          : isCompleted\n            ? "border-destructive/30 bg-destructive/5"\n            : "border-blue-500/30 bg-blue-500/5",\n      )}\n    >\n      <div className="flex items-start gap-3">\n        <span\n          className={cn(\n            "mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-full",\n            isAuthorized\n              ? "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300"\n              : isCompleted\n                ? "bg-destructive/10 text-destructive"\n                : "bg-blue-500/10 text-blue-700 dark:text-blue-300",\n          )}\n        >\n          <Icon className="size-4" />\n        </span>\n        <div className="min-w-0 flex-1 space-y-2">\n          <p className="font-medium text-sm">{authorizationTitle(part)}</p>\n          <p className="text-muted-foreground text-sm">{authorizationDescription(part)}</p>\n          {shouldShowInstructions ? (\n            <p className="text-muted-foreground text-sm">{instructions}</p>\n          ) : null}\n          {part.state === "required" && part.authorization?.userCode ? (\n            <div className="flex flex-wrap items-center gap-2 text-sm">\n              <span className="text-muted-foreground">Code</span>\n              <code className="rounded-md bg-background px-2 py-1 font-mono">\n                {part.authorization.userCode}\n              </code>\n            </div>\n          ) : null}\n          {part.state === "required" && part.authorization?.url ? (\n            <Button asChild size="sm">\n              <a href={part.authorization.url} rel="noreferrer" target="_blank">\n                <ExternalLinkIcon className="size-4" />\n                Sign in with {part.displayName}\n              </a>\n            </Button>\n          ) : null}\n        </div>\n      </div>\n    </div>\n  );\n}\n\nfunction authorizationTitle(part: EveAuthorizationPart): string {\n  if (part.state === "required") {\n    return `Connect ${part.displayName}`;\n  }\n  if (part.outcome === "authorized") {\n    return `${part.displayName} connected`;\n  }\n  return `${part.displayName} authorization ${formatAuthorizationOutcome(part.outcome)}`;\n}\n\nfunction authorizationDescription(part: EveAuthorizationPart): string {\n  if (part.state === "required") {\n    return part.description;\n  }\n  if (part.outcome === "authorized") {\n    return `${part.displayName} connected.`;\n  }\n  const tail = part.reason !== undefined ? ` (${part.reason})` : "";\n  return `${part.displayName} authorization ${formatAuthorizationOutcome(part.outcome)}${tail}.`;\n}\n\nfunction formatAuthorizationOutcome(outcome: NonNullable<EveAuthorizationPart["outcome"]>): string {\n  switch (outcome) {\n    case "authorized":\n      return "authorized";\n    case "declined":\n      return "declined";\n    case "failed":\n      return "failed";\n    case "timed-out":\n      return "timed out";\n  }\n}\n\nfunction formatBytes(size: number | undefined): string | undefined {\n  if (size === undefined) {\n    return undefined;\n  }\n  if (size < 1024) {\n    return `${size} B`;\n  }\n  if (size < 1024 * 1024) {\n    return `${(size / 1024).toFixed(1)} KB`;\n  }\n  return `${(size / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nfunction InputRequestActions({\n  canRespond,\n  onInputResponses,\n  part,\n}: {\n  readonly canRespond: boolean;\n  readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n  readonly part: EveDynamicToolPart;\n}) {\n  const inputRequest = part.toolMetadata?.eve?.inputRequest;\n  if (!inputRequest) {\n    return null;\n  }\n\n  const inputResponse = part.toolMetadata?.eve?.inputResponse;\n  const selectedOption = inputRequest.options?.find(\n    (option) => option.id === inputResponse?.optionId,\n  );\n\n  return (\n    <div className="space-y-3 rounded-md border border-yellow-500/30 bg-yellow-500/5 p-3">\n      <p className="text-muted-foreground text-sm">{inputRequest.prompt}</p>\n      {inputResponse ? (\n        <p className="font-medium text-sm">\n          Responded: {selectedOption?.label ?? inputResponse.text ?? inputResponse.optionId}\n        </p>\n      ) : (\n        <div className="flex flex-wrap gap-2">\n          {inputRequest.options?.map((option) => (\n            <Button\n              disabled={!canRespond}\n              key={option.id}\n              onClick={() => {\n                void onInputResponses([\n                  {\n                    optionId: option.id,\n                    requestId: inputRequest.requestId,\n                  },\n                ]);\n              }}\n              size="sm"\n              type="button"\n              variant={option.style === "danger" ? "destructive" : "default"}\n            >\n              {option.label}\n            </Button>\n          ))}\n        </div>\n      )}\n    </div>\n  );\n}\n\nfunction partKey(part: EveMessagePart, index: number): string {\n  switch (part.type) {\n    case "authorization":\n      return `authorization:${part.turnId}:${part.stepIndex}:${part.name}`;\n    case "dynamic-tool":\n      return part.toolCallId;\n    default:\n      return `${part.type}:${index}`;\n  }\n}\n';
    readonly "app/apple-icon.tsx": 'import { ImageResponse } from "next/og";\n\nexport const size = {\n  width: 180,\n  height: 180,\n};\n\nexport const contentType = "image/png";\n\nexport default function AppleIcon() {\n  return new ImageResponse(\n    <svg fill="none" viewBox="0 0 102 102" xmlns="http://www.w3.org/2000/svg">\n      <path d="M0 0h102v102H0z" fill="#000" />\n      <path\n        d="M49.28 66.94 75.03 34.96h-6.89L47.91 60.11l-5.49 6.83h6.86ZM0 34.96h42.4v5.11H0zm0 13.32h27.66v5.11H0zm0 13.54h27.66v5.11H0zm69.63-26.86H102v5.11H69.63zm4.71 13.32H102v5.11H74.34zm0 13.54H102v5.11H74.34z"\n        fill="#fff"\n      />\n    </svg>,\n    size,\n  );\n}\n';
    readonly "app/globals.css": '@import "tailwindcss";\n@source "../node_modules/streamdown/dist/*.js";\n\n@theme inline {\n  --color-background: var(--background);\n  --color-foreground: var(--foreground);\n  --color-card: var(--card);\n  --color-card-foreground: var(--card-foreground);\n  --color-popover: var(--popover);\n  --color-popover-foreground: var(--popover-foreground);\n  --color-primary: var(--primary);\n  --color-primary-foreground: var(--primary-foreground);\n  --color-secondary: var(--secondary);\n  --color-secondary-foreground: var(--secondary-foreground);\n  --color-muted: var(--muted);\n  --color-muted-foreground: var(--muted-foreground);\n  --color-accent: var(--accent);\n  --color-accent-foreground: var(--accent-foreground);\n  --color-destructive: var(--destructive);\n  --color-border: var(--border);\n  --color-input: var(--input);\n  --color-ring: var(--ring);\n  --radius-sm: calc(var(--radius) - 4px);\n  --radius-md: calc(var(--radius) - 2px);\n  --radius-lg: var(--radius);\n  --radius-xl: calc(var(--radius) + 4px);\n  --font-sans: "Geist", "Geist Fallback", ui-sans-serif, system-ui, sans-serif;\n  --font-mono: "Geist Mono", "Geist Mono Fallback", ui-monospace, monospace;\n}\n\n:root {\n  color-scheme: light;\n  /* Soft neutral page with white elevated surfaces so cards/composer pop. */\n  --background: oklch(0.971 0 0);\n  --foreground: oklch(0.16 0 0);\n  --card: oklch(1 0 0);\n  --card-foreground: oklch(0.16 0 0);\n  --popover: oklch(1 0 0);\n  --popover-foreground: oklch(0.16 0 0);\n  --primary: oklch(0.19 0 0);\n  --primary-foreground: oklch(0.985 0 0);\n  --secondary: oklch(0.94 0 0);\n  --secondary-foreground: oklch(0.19 0 0);\n  --muted: oklch(0.94 0 0);\n  --muted-foreground: oklch(0.6 0 0);\n  --accent: oklch(0.94 0 0);\n  --accent-foreground: oklch(0.19 0 0);\n  --destructive: oklch(0.577 0.245 27.325);\n  --border: oklch(0.916 0 0);\n  --input: oklch(0.916 0 0);\n  --ring: oklch(0.708 0 0);\n  --radius: 0.625rem;\n}\n\n@media (prefers-color-scheme: dark) {\n  :root {\n    color-scheme: dark;\n    --background: oklch(0.145 0 0);\n    --foreground: oklch(0.985 0 0);\n    --card: oklch(0.205 0 0);\n    --card-foreground: oklch(0.985 0 0);\n    --popover: oklch(0.205 0 0);\n    --popover-foreground: oklch(0.985 0 0);\n    --primary: oklch(0.922 0 0);\n    --primary-foreground: oklch(0.205 0 0);\n    --secondary: oklch(0.269 0 0);\n    --secondary-foreground: oklch(0.985 0 0);\n    --muted: oklch(0.269 0 0);\n    --muted-foreground: oklch(0.708 0 0);\n    --accent: oklch(0.269 0 0);\n    --accent-foreground: oklch(0.985 0 0);\n    --destructive: oklch(0.704 0.191 22.216);\n    --border: oklch(1 0 0 / 10%);\n    --input: oklch(1 0 0 / 15%);\n    --ring: oklch(0.556 0 0);\n  }\n}\n\n* {\n  border-color: var(--border);\n}\n\nhtml {\n  height: 100%;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\nbody {\n  min-height: 100%;\n  margin: 0;\n  background: var(--background);\n  font-family: var(--font-sans);\n}\n\nbutton,\ninput,\ntextarea {\n  font: inherit;\n}\n';
    readonly "app/icon.svg": '<svg width="102" height="102" viewBox="0 0 102 102" fill="none" xmlns="http://www.w3.org/2000/svg">\n  <path fill="#000" d="M0 0h102v102H0z" />\n  <path\n    fill="#fff"\n    d="M49.28 66.94 75.03 34.96h-6.89L47.91 60.11l-5.49 6.83h6.86ZM0 34.96h42.4v5.11H0zm0 13.32h27.66v5.11H0zm0 13.54h27.66v5.11H0zm69.63-26.86H102v5.11H69.63zm4.71 13.32H102v5.11H74.34zm0 13.54H102v5.11H74.34z"\n  />\n</svg>\n';
    readonly "app/layout.tsx": 'import type { Metadata } from "next";\nimport { Geist, Geist_Mono } from "next/font/google";\nimport type { ReactNode } from "react";\nimport { TooltipProvider } from "@/components/ui/tooltip";\nimport { cn } from "@/lib/utils";\nimport "./globals.css";\n\nconst sans = Geist({\n  variable: "--font-sans",\n  subsets: ["latin"],\n  weight: "variable",\n  display: "swap",\n});\n\nconst mono = Geist_Mono({\n  variable: "--font-mono",\n  subsets: ["latin"],\n  weight: "variable",\n  display: "swap",\n});\n\nexport const metadata: Metadata = {\n  title: "__EVE_INIT_APP_NAME__",\n  description: "A Next.js starter for eve agents with AI Elements.",\n};\n\nexport default function RootLayout({ children }: { readonly children: ReactNode }) {\n  return (\n    <html className={cn(sans.variable, mono.variable)} lang="en">\n      <body>\n        <TooltipProvider>{children}</TooltipProvider>\n      </body>\n    </html>\n  );\n}\n';
    readonly "app/page.tsx": 'import { AgentChat } from "@/app/_components/agent-chat";\n\nexport default function Page() {\n  return <AgentChat />;\n}\n';
    readonly "app/s/[sessionId]/page.tsx": 'import { AgentChat } from "@/app/_components/agent-chat";\n\nexport default async function SessionPage({\n  params,\n}: {\n  readonly params: Promise<{ readonly sessionId: string }>;\n}) {\n  const { sessionId } = await params;\n  return <AgentChat sessionId={sessionId} />;\n}\n';
    readonly "app/s/page.tsx": 'import { AgentChat } from "@/app/_components/agent-chat";\n\nexport default function NewSessionPage() {\n  return <AgentChat sessionless />;\n}\n';
    readonly "components/ai-elements/chain-of-thought.tsx": '"use client";\n\nimport { useControllableState } from "@radix-ui/react-use-controllable-state";\nimport { Badge } from "@/components/ui/badge";\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";\nimport { cn } from "@/lib/utils";\nimport type { LucideIcon } from "lucide-react";\nimport { BrainIcon, ChevronDownIcon, DotIcon } from "lucide-react";\nimport type { ComponentProps, ReactNode } from "react";\nimport { createContext, memo, useContext, useMemo } from "react";\n\ninterface ChainOfThoughtContextValue {\n  isOpen: boolean;\n  setIsOpen: (open: boolean) => void;\n}\n\nconst ChainOfThoughtContext = createContext<ChainOfThoughtContextValue | null>(null);\n\nconst useChainOfThought = () => {\n  const context = useContext(ChainOfThoughtContext);\n  if (!context) {\n    throw new Error("ChainOfThought components must be used within ChainOfThought");\n  }\n  return context;\n};\n\nexport type ChainOfThoughtProps = ComponentProps<"div"> & {\n  open?: boolean;\n  defaultOpen?: boolean;\n  onOpenChange?: (open: boolean) => void;\n};\n\nexport const ChainOfThought = memo(\n  ({\n    className,\n    open,\n    defaultOpen = false,\n    onOpenChange,\n    children,\n    ...props\n  }: ChainOfThoughtProps) => {\n    const [isOpen, setIsOpen] = useControllableState({\n      defaultProp: defaultOpen,\n      onChange: onOpenChange,\n      prop: open,\n    });\n\n    const chainOfThoughtContext = useMemo(() => ({ isOpen, setIsOpen }), [isOpen, setIsOpen]);\n\n    return (\n      <ChainOfThoughtContext.Provider value={chainOfThoughtContext}>\n        <div className={cn("not-prose w-full space-y-4", className)} {...props}>\n          {children}\n        </div>\n      </ChainOfThoughtContext.Provider>\n    );\n  },\n);\n\nexport type ChainOfThoughtHeaderProps = ComponentProps<typeof CollapsibleTrigger>;\n\nexport const ChainOfThoughtHeader = memo(\n  ({ className, children, ...props }: ChainOfThoughtHeaderProps) => {\n    const { isOpen, setIsOpen } = useChainOfThought();\n\n    return (\n      <Collapsible onOpenChange={setIsOpen} open={isOpen}>\n        <CollapsibleTrigger\n          className={cn(\n            "flex w-full items-center gap-2 text-muted-foreground text-sm transition-colors hover:text-foreground",\n            className,\n          )}\n          {...props}\n        >\n          <BrainIcon className="size-4" />\n          <span className="flex-1 text-left">{children ?? "Chain of Thought"}</span>\n          <ChevronDownIcon\n            className={cn("size-4 transition-transform", isOpen ? "rotate-180" : "rotate-0")}\n          />\n        </CollapsibleTrigger>\n      </Collapsible>\n    );\n  },\n);\n\nexport type ChainOfThoughtStepProps = ComponentProps<"div"> & {\n  icon?: LucideIcon;\n  label: ReactNode;\n  description?: ReactNode;\n  status?: "complete" | "active" | "pending";\n};\n\nconst stepStatusStyles = {\n  active: "text-foreground",\n  complete: "text-muted-foreground",\n  pending: "text-muted-foreground/50",\n};\n\nexport const ChainOfThoughtStep = memo(\n  ({\n    className,\n    icon: Icon = DotIcon,\n    label,\n    description,\n    status = "complete",\n    children,\n    ...props\n  }: ChainOfThoughtStepProps) => (\n    <div\n      className={cn(\n        "flex gap-2 text-sm",\n        stepStatusStyles[status],\n        "fade-in-0 slide-in-from-top-2 animate-in",\n        className,\n      )}\n      {...props}\n    >\n      <div className="relative mt-0.5">\n        <Icon className="size-4" />\n        <div className="absolute top-7 bottom-0 left-1/2 -mx-px w-px bg-border" />\n      </div>\n      <div className="flex-1 space-y-2 overflow-hidden">\n        <div>{label}</div>\n        {description && <div className="text-muted-foreground text-xs">{description}</div>}\n        {children}\n      </div>\n    </div>\n  ),\n);\n\nexport type ChainOfThoughtSearchResultsProps = ComponentProps<"div">;\n\nexport const ChainOfThoughtSearchResults = memo(\n  ({ className, ...props }: ChainOfThoughtSearchResultsProps) => (\n    <div className={cn("flex flex-wrap items-center gap-2", className)} {...props} />\n  ),\n);\n\nexport type ChainOfThoughtSearchResultProps = ComponentProps<typeof Badge>;\n\nexport const ChainOfThoughtSearchResult = memo(\n  ({ className, children, ...props }: ChainOfThoughtSearchResultProps) => (\n    <Badge\n      className={cn("gap-1 px-2 py-0.5 font-normal text-xs", className)}\n      variant="secondary"\n      {...props}\n    >\n      {children}\n    </Badge>\n  ),\n);\n\nexport type ChainOfThoughtContentProps = ComponentProps<typeof CollapsibleContent>;\n\nexport const ChainOfThoughtContent = memo(\n  ({ className, children, ...props }: ChainOfThoughtContentProps) => {\n    const { isOpen } = useChainOfThought();\n\n    return (\n      <Collapsible open={isOpen}>\n        <CollapsibleContent\n          className={cn(\n            "mt-2 space-y-3",\n            "data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-popover-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",\n            className,\n          )}\n          {...props}\n        >\n          {children}\n        </CollapsibleContent>\n      </Collapsible>\n    );\n  },\n);\n\nexport type ChainOfThoughtImageProps = ComponentProps<"div"> & {\n  caption?: string;\n};\n\nexport const ChainOfThoughtImage = memo(\n  ({ className, children, caption, ...props }: ChainOfThoughtImageProps) => (\n    <div className={cn("mt-2 space-y-2", className)} {...props}>\n      <div className="relative flex max-h-[22rem] items-center justify-center overflow-hidden rounded-lg bg-muted p-3">\n        {children}\n      </div>\n      {caption && <p className="text-muted-foreground text-xs">{caption}</p>}\n    </div>\n  ),\n);\n\nChainOfThought.displayName = "ChainOfThought";\nChainOfThoughtHeader.displayName = "ChainOfThoughtHeader";\nChainOfThoughtStep.displayName = "ChainOfThoughtStep";\nChainOfThoughtSearchResults.displayName = "ChainOfThoughtSearchResults";\nChainOfThoughtSearchResult.displayName = "ChainOfThoughtSearchResult";\nChainOfThoughtContent.displayName = "ChainOfThoughtContent";\nChainOfThoughtImage.displayName = "ChainOfThoughtImage";\n';
    readonly "components/ai-elements/code-block.tsx": '"use client";\n\nimport { Button } from "@/components/ui/button";\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue,\n} from "@/components/ui/select";\nimport { cn } from "@/lib/utils";\nimport { CheckIcon, CopyIcon } from "lucide-react";\nimport type { ComponentProps, CSSProperties, HTMLAttributes } from "react";\nimport {\n  createContext,\n  memo,\n  useCallback,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n} from "react";\nimport type { BundledLanguage, BundledTheme, HighlighterGeneric, ThemedToken } from "shiki";\nimport { createHighlighter } from "shiki";\n\n// Shiki uses bitflags for font styles: 1=italic, 2=bold, 4=underline\n// oxlint-disable-next-line eslint(no-bitwise)\nconst isItalic = (fontStyle: number | undefined) => fontStyle && fontStyle & 1;\n// oxlint-disable-next-line eslint(no-bitwise)\nconst isBold = (fontStyle: number | undefined) => fontStyle && fontStyle & 2;\nconst isUnderline = (fontStyle: number | undefined) =>\n  // oxlint-disable-next-line eslint(no-bitwise)\n  fontStyle && fontStyle & 4;\n\n// Transform tokens to include pre-computed keys to avoid noArrayIndexKey lint\ninterface KeyedToken {\n  token: ThemedToken;\n  key: string;\n}\ninterface KeyedLine {\n  tokens: KeyedToken[];\n  key: string;\n}\n\nconst addKeysToTokens = (lines: ThemedToken[][]): KeyedLine[] =>\n  lines.map((line, lineIdx) => ({\n    key: `line-${lineIdx}`,\n    tokens: line.map((token, tokenIdx) => ({\n      key: `line-${lineIdx}-${tokenIdx}`,\n      token,\n    })),\n  }));\n\n// Token rendering component\nconst TokenSpan = ({ token }: { token: ThemedToken }) => (\n  <span\n    className="dark:!bg-[var(--shiki-dark-bg)] dark:!text-[var(--shiki-dark)]"\n    style={\n      {\n        backgroundColor: token.bgColor,\n        color: token.color,\n        fontStyle: isItalic(token.fontStyle) ? "italic" : undefined,\n        fontWeight: isBold(token.fontStyle) ? "bold" : undefined,\n        textDecoration: isUnderline(token.fontStyle) ? "underline" : undefined,\n        ...token.htmlStyle,\n      } as CSSProperties\n    }\n  >\n    {token.content}\n  </span>\n);\n\n// Line number styles using CSS counters\nconst LINE_NUMBER_CLASSES = cn(\n  "block",\n  "before:content-[counter(line)]",\n  "before:inline-block",\n  "before:[counter-increment:line]",\n  "before:w-8",\n  "before:mr-4",\n  "before:text-right",\n  "before:text-muted-foreground/50",\n  "before:font-mono",\n  "before:select-none",\n);\n\n// Line rendering component\nconst LineSpan = ({\n  keyedLine,\n  showLineNumbers,\n}: {\n  keyedLine: KeyedLine;\n  showLineNumbers: boolean;\n}) => (\n  <span className={showLineNumbers ? LINE_NUMBER_CLASSES : "block"}>\n    {keyedLine.tokens.length === 0\n      ? "\\n"\n      : keyedLine.tokens.map(({ token, key }) => <TokenSpan key={key} token={token} />)}\n  </span>\n);\n\n// Types\ntype CodeBlockProps = HTMLAttributes<HTMLDivElement> & {\n  code: string;\n  language: BundledLanguage;\n  showLineNumbers?: boolean;\n};\n\ninterface TokenizedCode {\n  tokens: ThemedToken[][];\n  fg: string;\n  bg: string;\n}\n\ninterface CodeBlockContextType {\n  code: string;\n}\n\n// Context\nconst CodeBlockContext = createContext<CodeBlockContextType>({\n  code: "",\n});\n\n// Highlighter cache (singleton per language)\nconst highlighterCache = new Map<\n  string,\n  Promise<HighlighterGeneric<BundledLanguage, BundledTheme>>\n>();\n\n// Token cache\nconst tokensCache = new Map<string, TokenizedCode>();\n\n// Subscribers for async token updates\nconst subscribers = new Map<string, Set<(result: TokenizedCode) => void>>();\n\nconst getTokensCacheKey = (code: string, language: BundledLanguage) => {\n  const start = code.slice(0, 100);\n  const end = code.length > 100 ? code.slice(-100) : "";\n  return `${language}:${code.length}:${start}:${end}`;\n};\n\nconst getHighlighter = (\n  language: BundledLanguage,\n): Promise<HighlighterGeneric<BundledLanguage, BundledTheme>> => {\n  const cached = highlighterCache.get(language);\n  if (cached) {\n    return cached;\n  }\n\n  const highlighterPromise = createHighlighter({\n    langs: [language],\n    themes: ["github-light", "github-dark"],\n  });\n\n  highlighterCache.set(language, highlighterPromise);\n  return highlighterPromise;\n};\n\n// Create raw tokens for immediate display while highlighting loads\nconst createRawTokens = (code: string): TokenizedCode => ({\n  bg: "transparent",\n  fg: "inherit",\n  tokens: code.split("\\n").map((line) =>\n    line === ""\n      ? []\n      : [\n          {\n            color: "inherit",\n            content: line,\n          } as ThemedToken,\n        ],\n  ),\n});\n\n// Synchronous highlight with callback for async results\nexport const highlightCode = (\n  code: string,\n  language: BundledLanguage,\n  // oxlint-disable-next-line eslint-plugin-promise(prefer-await-to-callbacks)\n  callback?: (result: TokenizedCode) => void,\n): TokenizedCode | null => {\n  const tokensCacheKey = getTokensCacheKey(code, language);\n\n  // Return cached result if available\n  const cached = tokensCache.get(tokensCacheKey);\n  if (cached) {\n    return cached;\n  }\n\n  // Subscribe callback if provided\n  if (callback) {\n    if (!subscribers.has(tokensCacheKey)) {\n      subscribers.set(tokensCacheKey, new Set());\n    }\n    subscribers.get(tokensCacheKey)?.add(callback);\n  }\n\n  // Start highlighting in background - fire-and-forget async pattern\n  getHighlighter(language)\n    // oxlint-disable-next-line eslint-plugin-promise(prefer-await-to-then)\n    .then((highlighter) => {\n      const availableLangs = highlighter.getLoadedLanguages();\n      const langToUse = availableLangs.includes(language) ? language : "text";\n\n      const result = highlighter.codeToTokens(code, {\n        lang: langToUse,\n        themes: {\n          dark: "github-dark",\n          light: "github-light",\n        },\n      });\n\n      const tokenized: TokenizedCode = {\n        bg: result.bg ?? "transparent",\n        fg: result.fg ?? "inherit",\n        tokens: result.tokens,\n      };\n\n      // Cache the result\n      tokensCache.set(tokensCacheKey, tokenized);\n\n      // Notify all subscribers\n      const subs = subscribers.get(tokensCacheKey);\n      if (subs) {\n        for (const sub of subs) {\n          sub(tokenized);\n        }\n        subscribers.delete(tokensCacheKey);\n      }\n    })\n    // oxlint-disable-next-line eslint-plugin-promise(prefer-await-to-then), eslint-plugin-promise(prefer-await-to-callbacks)\n    .catch((error) => {\n      console.error("Failed to highlight code:", error);\n      subscribers.delete(tokensCacheKey);\n    });\n\n  return null;\n};\n\nconst CodeBlockBody = memo(\n  ({\n    tokenized,\n    showLineNumbers,\n    className,\n  }: {\n    tokenized: TokenizedCode;\n    showLineNumbers: boolean;\n    className?: string;\n  }) => {\n    const preStyle = useMemo(\n      () => ({\n        backgroundColor: tokenized.bg,\n        color: tokenized.fg,\n      }),\n      [tokenized.bg, tokenized.fg],\n    );\n\n    const keyedLines = useMemo(() => addKeysToTokens(tokenized.tokens), [tokenized.tokens]);\n\n    return (\n      <pre\n        className={cn(\n          "dark:!bg-[var(--shiki-dark-bg)] dark:!text-[var(--shiki-dark)] m-0 p-4 text-sm",\n          className,\n        )}\n        style={preStyle}\n      >\n        <code\n          className={cn(\n            "font-mono text-sm",\n            showLineNumbers && "[counter-increment:line_0] [counter-reset:line]",\n          )}\n        >\n          {keyedLines.map((keyedLine) => (\n            <LineSpan key={keyedLine.key} keyedLine={keyedLine} showLineNumbers={showLineNumbers} />\n          ))}\n        </code>\n      </pre>\n    );\n  },\n  (prevProps, nextProps) =>\n    prevProps.tokenized === nextProps.tokenized &&\n    prevProps.showLineNumbers === nextProps.showLineNumbers &&\n    prevProps.className === nextProps.className,\n);\n\nCodeBlockBody.displayName = "CodeBlockBody";\n\nexport const CodeBlockContainer = ({\n  className,\n  language,\n  style,\n  ...props\n}: HTMLAttributes<HTMLDivElement> & { language: string }) => (\n  <div\n    className={cn(\n      "group relative w-full overflow-hidden rounded-md border bg-background text-foreground",\n      className,\n    )}\n    data-language={language}\n    style={{\n      containIntrinsicSize: "auto 200px",\n      contentVisibility: "auto",\n      ...style,\n    }}\n    {...props}\n  />\n);\n\nexport const CodeBlockHeader = ({\n  children,\n  className,\n  ...props\n}: HTMLAttributes<HTMLDivElement>) => (\n  <div\n    className={cn(\n      "flex items-center justify-between border-b bg-muted/80 px-3 py-2 text-muted-foreground text-xs",\n      className,\n    )}\n    {...props}\n  >\n    {children}\n  </div>\n);\n\nexport const CodeBlockTitle = ({\n  children,\n  className,\n  ...props\n}: HTMLAttributes<HTMLDivElement>) => (\n  <div className={cn("flex items-center gap-2", className)} {...props}>\n    {children}\n  </div>\n);\n\nexport const CodeBlockFilename = ({\n  children,\n  className,\n  ...props\n}: HTMLAttributes<HTMLSpanElement>) => (\n  <span className={cn("font-mono", className)} {...props}>\n    {children}\n  </span>\n);\n\nexport const CodeBlockActions = ({\n  children,\n  className,\n  ...props\n}: HTMLAttributes<HTMLDivElement>) => (\n  <div className={cn("-my-1 -mr-1 flex items-center gap-2", className)} {...props}>\n    {children}\n  </div>\n);\n\nexport const CodeBlockContent = ({\n  code,\n  language,\n  showLineNumbers = false,\n}: {\n  code: string;\n  language: BundledLanguage;\n  showLineNumbers?: boolean;\n}) => {\n  // Memoized raw tokens for immediate display\n  const rawTokens = useMemo(() => createRawTokens(code), [code]);\n\n  // Synchronous cache lookup — avoids setState in effect for cached results\n  const syncTokens = useMemo(\n    () => highlightCode(code, language) ?? rawTokens,\n    [code, language, rawTokens],\n  );\n\n  // Async highlighting result (populated after shiki loads)\n  const [asyncTokens, setAsyncTokens] = useState<TokenizedCode | null>(null);\n  const asyncKeyRef = useRef({ code, language });\n\n  // Invalidate stale async tokens synchronously during render\n  if (asyncKeyRef.current.code !== code || asyncKeyRef.current.language !== language) {\n    asyncKeyRef.current = { code, language };\n    setAsyncTokens(null);\n  }\n\n  useEffect(() => {\n    let cancelled = false;\n\n    highlightCode(code, language, (result) => {\n      if (!cancelled) {\n        setAsyncTokens(result);\n      }\n    });\n\n    return () => {\n      cancelled = true;\n    };\n  }, [code, language]);\n\n  const tokenized = asyncTokens ?? syncTokens;\n\n  return (\n    <div className="relative overflow-auto">\n      <CodeBlockBody showLineNumbers={showLineNumbers} tokenized={tokenized} />\n    </div>\n  );\n};\n\nexport const CodeBlock = ({\n  code,\n  language,\n  showLineNumbers = false,\n  className,\n  children,\n  ...props\n}: CodeBlockProps) => {\n  const contextValue = useMemo(() => ({ code }), [code]);\n\n  return (\n    <CodeBlockContext.Provider value={contextValue}>\n      <CodeBlockContainer className={className} language={language} {...props}>\n        {children}\n        <CodeBlockContent code={code} language={language} showLineNumbers={showLineNumbers} />\n      </CodeBlockContainer>\n    </CodeBlockContext.Provider>\n  );\n};\n\nexport type CodeBlockCopyButtonProps = ComponentProps<typeof Button> & {\n  onCopy?: () => void;\n  onError?: (error: Error) => void;\n  timeout?: number;\n};\n\nexport const CodeBlockCopyButton = ({\n  onCopy,\n  onError,\n  timeout = 2000,\n  children,\n  className,\n  ...props\n}: CodeBlockCopyButtonProps) => {\n  const [isCopied, setIsCopied] = useState(false);\n  const timeoutRef = useRef<number>(0);\n  const { code } = useContext(CodeBlockContext);\n\n  const copyToClipboard = useCallback(async () => {\n    if (typeof window === "undefined" || !navigator?.clipboard?.writeText) {\n      onError?.(new Error("Clipboard API not available"));\n      return;\n    }\n\n    try {\n      if (!isCopied) {\n        await navigator.clipboard.writeText(code);\n        setIsCopied(true);\n        onCopy?.();\n        timeoutRef.current = window.setTimeout(() => setIsCopied(false), timeout);\n      }\n    } catch (error) {\n      onError?.(error as Error);\n    }\n  }, [code, onCopy, onError, timeout, isCopied]);\n\n  useEffect(\n    () => () => {\n      window.clearTimeout(timeoutRef.current);\n    },\n    [],\n  );\n\n  const Icon = isCopied ? CheckIcon : CopyIcon;\n\n  return (\n    <Button\n      className={cn("shrink-0", className)}\n      onClick={copyToClipboard}\n      size="icon"\n      variant="ghost"\n      {...props}\n    >\n      {children ?? <Icon size={14} />}\n    </Button>\n  );\n};\n\nexport type CodeBlockLanguageSelectorProps = ComponentProps<typeof Select>;\n\nexport const CodeBlockLanguageSelector = (props: CodeBlockLanguageSelectorProps) => (\n  <Select {...props} />\n);\n\nexport type CodeBlockLanguageSelectorTriggerProps = ComponentProps<typeof SelectTrigger>;\n\nexport const CodeBlockLanguageSelectorTrigger = ({\n  className,\n  ...props\n}: CodeBlockLanguageSelectorTriggerProps) => (\n  <SelectTrigger\n    className={cn("h-7 border-none bg-transparent px-2 text-xs shadow-none", className)}\n    size="sm"\n    {...props}\n  />\n);\n\nexport type CodeBlockLanguageSelectorValueProps = ComponentProps<typeof SelectValue>;\n\nexport const CodeBlockLanguageSelectorValue = (props: CodeBlockLanguageSelectorValueProps) => (\n  <SelectValue {...props} />\n);\n\nexport type CodeBlockLanguageSelectorContentProps = ComponentProps<typeof SelectContent>;\n\nexport const CodeBlockLanguageSelectorContent = ({\n  align = "end",\n  ...props\n}: CodeBlockLanguageSelectorContentProps) => <SelectContent align={align} {...props} />;\n\nexport type CodeBlockLanguageSelectorItemProps = ComponentProps<typeof SelectItem>;\n\nexport const CodeBlockLanguageSelectorItem = (props: CodeBlockLanguageSelectorItemProps) => (\n  <SelectItem {...props} />\n);\n';
    readonly "components/ai-elements/conversation.tsx": '"use client";\n\nimport { Button } from "@/components/ui/button";\nimport { cn } from "@/lib/utils";\nimport type { UIMessage } from "ai";\nimport { ArrowDownIcon, DownloadIcon } from "lucide-react";\nimport type { ComponentProps } from "react";\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";\nimport { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";\n\nexport type ConversationProps = ComponentProps<typeof StickToBottom> & {\n  scrollRestorationKey?: string;\n};\n\nexport const Conversation = ({\n  children,\n  className,\n  initial,\n  scrollRestorationKey,\n  ...props\n}: ConversationProps) => (\n  <StickToBottom\n    className={cn("relative flex-1 overflow-y-hidden", className)}\n    initial={initial ?? (scrollRestorationKey === undefined ? "smooth" : false)}\n    resize="smooth"\n    role="log"\n    {...props}\n  >\n    {typeof children === "function" ? (\n      (context) => (\n        <>\n          {children(context)}\n          {scrollRestorationKey === undefined ? null : (\n            <ConversationScrollRestoration storageKey={scrollRestorationKey} />\n          )}\n        </>\n      )\n    ) : (\n      <>\n        {children}\n        {scrollRestorationKey === undefined ? null : (\n          <ConversationScrollRestoration storageKey={scrollRestorationKey} />\n        )}\n      </>\n    )}\n  </StickToBottom>\n);\n\nfunction ConversationScrollRestoration({ storageKey }: { readonly storageKey: string }) {\n  const { scrollRef, scrollToBottom, state } = useStickToBottomContext();\n  const restoredKeyRef = useRef<string | undefined>(undefined);\n\n  useLayoutEffect(() => {\n    const scrollElement = scrollRef.current;\n    if (scrollElement === null) return;\n\n    if (restoredKeyRef.current !== storageKey) {\n      const saved = readScrollPosition(sessionStorage.getItem(storageKey));\n      if (saved?.atBottom === false) {\n        scrollElement.scrollTop = saved.scrollTop;\n        requestAnimationFrame(() => {\n          scrollElement.scrollTop = saved.scrollTop;\n        });\n      } else {\n        scrollElement.scrollTop = scrollElement.scrollHeight;\n        scrollToBottom({ animation: "instant", ignoreEscapes: true });\n      }\n      restoredKeyRef.current = storageKey;\n    }\n\n    const saveNow = () => {\n      sessionStorage.setItem(\n        storageKey,\n        JSON.stringify({\n          atBottom: state.isAtBottom || state.isNearBottom,\n          scrollTop: scrollElement.scrollTop,\n        }),\n      );\n    };\n    let frame: number | undefined;\n    const scheduleSave = () => {\n      if (frame !== undefined) return;\n      frame = requestAnimationFrame(() => {\n        frame = undefined;\n        saveNow();\n      });\n    };\n    scrollElement.addEventListener("scroll", scheduleSave, { passive: true });\n    window.addEventListener("pagehide", saveNow);\n    return () => {\n      scrollElement.removeEventListener("scroll", scheduleSave);\n      window.removeEventListener("pagehide", saveNow);\n      if (frame !== undefined) cancelAnimationFrame(frame);\n      saveNow();\n    };\n  }, [scrollRef, scrollToBottom, state, storageKey]);\n\n  return null;\n}\n\nfunction readScrollPosition(value: string | null):\n  | {\n      readonly atBottom: boolean;\n      readonly scrollTop: number;\n    }\n  | undefined {\n  if (value === null) return undefined;\n  try {\n    const parsed = JSON.parse(value) as { atBottom?: unknown; scrollTop?: unknown };\n    return typeof parsed.atBottom === "boolean" && typeof parsed.scrollTop === "number"\n      ? { atBottom: parsed.atBottom, scrollTop: parsed.scrollTop }\n      : undefined;\n  } catch {\n    return undefined;\n  }\n}\n\nexport type ConversationContentProps = ComponentProps<typeof StickToBottom.Content>;\n\nexport const ConversationContent = ({ className, ...props }: ConversationContentProps) => (\n  <StickToBottom.Content className={cn("flex flex-col gap-8 p-4", className)} {...props} />\n);\n\nexport type ConversationTopFadeProps = ComponentProps<"div">;\n\nexport const ConversationTopFade = ({ className, ...props }: ConversationTopFadeProps) => {\n  const { contentRef, scrollRef } = useStickToBottomContext();\n  const [isVisible, setIsVisible] = useState(false);\n\n  useEffect(() => {\n    const scrollElement = scrollRef.current;\n    if (scrollElement === null) return;\n\n    const updateVisibility = () => {\n      setIsVisible(scrollElement.scrollTop > 0);\n    };\n\n    updateVisibility();\n    scrollElement.addEventListener("scroll", updateVisibility, { passive: true });\n\n    const resizeObserver = new ResizeObserver(updateVisibility);\n    resizeObserver.observe(scrollElement);\n    if (contentRef.current !== null) {\n      resizeObserver.observe(contentRef.current);\n    }\n\n    return () => {\n      scrollElement.removeEventListener("scroll", updateVisibility);\n      resizeObserver.disconnect();\n    };\n  }, [contentRef, scrollRef]);\n\n  return (\n    <div\n      {...props}\n      aria-hidden\n      className={cn(\n        "pointer-events-none absolute inset-x-0 top-0 z-10 h-6 bg-linear-to-b from-background via-background/80 to-transparent transition-opacity duration-150",\n        isVisible ? "opacity-100" : "opacity-0",\n        className,\n      )}\n      data-slot="conversation-top-fade"\n    />\n  );\n};\n\nexport type ConversationEmptyStateProps = ComponentProps<"div"> & {\n  title?: string;\n  description?: string;\n  icon?: React.ReactNode;\n};\n\nexport const ConversationEmptyState = ({\n  className,\n  title = "No messages yet",\n  description = "Start a conversation to see messages here",\n  icon,\n  children,\n  ...props\n}: ConversationEmptyStateProps) => (\n  <div\n    className={cn(\n      "flex size-full flex-col items-center justify-center gap-3 p-8 text-center",\n      className,\n    )}\n    {...props}\n  >\n    {children ?? (\n      <>\n        {icon && <div className="text-muted-foreground">{icon}</div>}\n        <div className="space-y-1">\n          <h3 className="font-medium text-sm">{title}</h3>\n          {description && <p className="text-muted-foreground text-sm">{description}</p>}\n        </div>\n      </>\n    )}\n  </div>\n);\n\nexport type ConversationScrollButtonProps = ComponentProps<typeof Button>;\n\nexport const ConversationScrollButton = ({\n  className,\n  ...props\n}: ConversationScrollButtonProps) => {\n  const { isAtBottom, scrollToBottom } = useStickToBottomContext();\n  const [isReady, setIsReady] = useState(false);\n\n  useEffect(() => setIsReady(true), []);\n\n  const handleScrollToBottom = useCallback(() => {\n    scrollToBottom();\n  }, [scrollToBottom]);\n\n  return (\n    isReady &&\n    !isAtBottom && (\n      <Button\n        aria-label="Scroll to bottom"\n        className={cn(\n          "absolute bottom-32 left-[50%] translate-x-[-50%] rounded-full dark:bg-background dark:hover:bg-muted",\n          className,\n        )}\n        onClick={handleScrollToBottom}\n        size="icon"\n        type="button"\n        variant="outline"\n        {...props}\n      >\n        <ArrowDownIcon className="size-4" />\n      </Button>\n    )\n  );\n};\n\nconst getMessageText = (message: UIMessage): string =>\n  message.parts\n    .filter((part) => part.type === "text")\n    .map((part) => part.text)\n    .join("");\n\nexport type ConversationDownloadProps = Omit<ComponentProps<typeof Button>, "onClick"> & {\n  messages: UIMessage[];\n  filename?: string;\n  formatMessage?: (message: UIMessage, index: number) => string;\n};\n\nconst defaultFormatMessage = (message: UIMessage): string => {\n  const roleLabel = message.role.charAt(0).toUpperCase() + message.role.slice(1);\n  return `**${roleLabel}:** ${getMessageText(message)}`;\n};\n\nexport const messagesToMarkdown = (\n  messages: UIMessage[],\n  formatMessage: (message: UIMessage, index: number) => string = defaultFormatMessage,\n): string => messages.map((msg, i) => formatMessage(msg, i)).join("\\n\\n");\n\nexport const ConversationDownload = ({\n  messages,\n  filename = "conversation.md",\n  formatMessage = defaultFormatMessage,\n  className,\n  children,\n  ...props\n}: ConversationDownloadProps) => {\n  const handleDownload = useCallback(() => {\n    const markdown = messagesToMarkdown(messages, formatMessage);\n    const blob = new Blob([markdown], { type: "text/markdown" });\n    const url = URL.createObjectURL(blob);\n    const link = document.createElement("a");\n    link.href = url;\n    link.download = filename;\n    document.body.append(link);\n    link.click();\n    link.remove();\n    URL.revokeObjectURL(url);\n  }, [messages, filename, formatMessage]);\n\n  return (\n    <Button\n      className={cn(\n        "absolute top-4 right-4 rounded-full dark:bg-background dark:hover:bg-muted",\n        className,\n      )}\n      onClick={handleDownload}\n      size="icon"\n      type="button"\n      variant="outline"\n      {...props}\n    >\n      {children ?? <DownloadIcon className="size-4" />}\n    </Button>\n  );\n};\n';
    readonly "components/ai-elements/message.tsx": '"use client";\n\nimport { Button } from "@/components/ui/button";\nimport { ButtonGroup, ButtonGroupText } from "@/components/ui/button-group";\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";\nimport { cn } from "@/lib/utils";\nimport { cjk } from "@streamdown/cjk";\nimport { code } from "@streamdown/code";\nimport { math } from "@streamdown/math";\nimport { mermaid } from "@streamdown/mermaid";\nimport type { UIMessage } from "ai";\nimport { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";\nimport type { ComponentProps, HTMLAttributes, ReactElement } from "react";\nimport { createContext, memo, useCallback, useContext, useEffect, useMemo, useState } from "react";\nimport { Streamdown } from "streamdown";\n\nexport type MessageProps = HTMLAttributes<HTMLDivElement> & {\n  from: UIMessage["role"];\n};\n\nexport const Message = ({ className, from, ...props }: MessageProps) => (\n  <div\n    className={cn(\n      "group flex w-full max-w-[95%] flex-col gap-2",\n      from === "user" ? "is-user ml-auto justify-end" : "is-assistant",\n      className,\n    )}\n    {...props}\n  />\n);\n\nexport type MessageContentProps = HTMLAttributes<HTMLDivElement>;\n\nexport const MessageContent = ({ children, className, ...props }: MessageContentProps) => (\n  <div\n    className={cn(\n      "is-user:dark flex w-fit min-w-0 max-w-full flex-col gap-2 overflow-hidden text-sm",\n      "group-[.is-user]:ml-auto group-[.is-user]:rounded-2xl group-[.is-user]:bg-primary group-[.is-user]:px-4 group-[.is-user]:py-2.5 group-[.is-user]:text-primary-foreground",\n      "group-[.is-assistant]:w-full group-[.is-assistant]:text-foreground",\n      "group-data-[optimistic=true]:opacity-70",\n      className,\n    )}\n    {...props}\n  >\n    {children}\n  </div>\n);\n\nexport type MessageActionsProps = ComponentProps<"div">;\n\nexport const MessageActions = ({ className, children, ...props }: MessageActionsProps) => (\n  <div className={cn("flex items-center gap-1", className)} {...props}>\n    {children}\n  </div>\n);\n\nexport type MessageActionProps = ComponentProps<typeof Button> & {\n  tooltip?: string;\n  label?: string;\n};\n\nexport const MessageAction = ({\n  tooltip,\n  children,\n  label,\n  variant = "ghost",\n  size = "icon-sm",\n  ...props\n}: MessageActionProps) => {\n  const button = (\n    <Button size={size} type="button" variant={variant} {...props}>\n      {children}\n      <span className="sr-only">{label || tooltip}</span>\n    </Button>\n  );\n\n  if (tooltip) {\n    return (\n      <TooltipProvider>\n        <Tooltip>\n          <TooltipTrigger asChild>{button}</TooltipTrigger>\n          <TooltipContent>\n            <p>{tooltip}</p>\n          </TooltipContent>\n        </Tooltip>\n      </TooltipProvider>\n    );\n  }\n\n  return button;\n};\n\ninterface MessageBranchContextType {\n  currentBranch: number;\n  totalBranches: number;\n  goToPrevious: () => void;\n  goToNext: () => void;\n  branches: ReactElement[];\n  setBranches: (branches: ReactElement[]) => void;\n}\n\nconst MessageBranchContext = createContext<MessageBranchContextType | null>(null);\n\nconst useMessageBranch = () => {\n  const context = useContext(MessageBranchContext);\n\n  if (!context) {\n    throw new Error("MessageBranch components must be used within MessageBranch");\n  }\n\n  return context;\n};\n\nexport type MessageBranchProps = HTMLAttributes<HTMLDivElement> & {\n  defaultBranch?: number;\n  onBranchChange?: (branchIndex: number) => void;\n};\n\nexport const MessageBranch = ({\n  defaultBranch = 0,\n  onBranchChange,\n  className,\n  ...props\n}: MessageBranchProps) => {\n  const [currentBranch, setCurrentBranch] = useState(defaultBranch);\n  const [branches, setBranches] = useState<ReactElement[]>([]);\n\n  const handleBranchChange = useCallback(\n    (newBranch: number) => {\n      setCurrentBranch(newBranch);\n      onBranchChange?.(newBranch);\n    },\n    [onBranchChange],\n  );\n\n  const goToPrevious = useCallback(() => {\n    const newBranch = currentBranch > 0 ? currentBranch - 1 : branches.length - 1;\n    handleBranchChange(newBranch);\n  }, [currentBranch, branches.length, handleBranchChange]);\n\n  const goToNext = useCallback(() => {\n    const newBranch = currentBranch < branches.length - 1 ? currentBranch + 1 : 0;\n    handleBranchChange(newBranch);\n  }, [currentBranch, branches.length, handleBranchChange]);\n\n  const contextValue = useMemo<MessageBranchContextType>(\n    () => ({\n      branches,\n      currentBranch,\n      goToNext,\n      goToPrevious,\n      setBranches,\n      totalBranches: branches.length,\n    }),\n    [branches, currentBranch, goToNext, goToPrevious],\n  );\n\n  return (\n    <MessageBranchContext.Provider value={contextValue}>\n      <div className={cn("grid w-full gap-2 [&>div]:pb-0", className)} {...props} />\n    </MessageBranchContext.Provider>\n  );\n};\n\nexport type MessageBranchContentProps = HTMLAttributes<HTMLDivElement>;\n\nexport const MessageBranchContent = ({ children, ...props }: MessageBranchContentProps) => {\n  const { currentBranch, setBranches, branches } = useMessageBranch();\n  const childrenArray = useMemo(\n    () => (Array.isArray(children) ? children : [children]),\n    [children],\n  );\n\n  // Use useEffect to update branches when they change\n  useEffect(() => {\n    if (branches.length !== childrenArray.length) {\n      setBranches(childrenArray);\n    }\n  }, [childrenArray, branches, setBranches]);\n\n  return childrenArray.map((branch, index) => (\n    <div\n      className={cn(\n        "grid gap-2 overflow-hidden [&>div]:pb-0",\n        index === currentBranch ? "block" : "hidden",\n      )}\n      key={branch.key}\n      {...props}\n    >\n      {branch}\n    </div>\n  ));\n};\n\nexport type MessageBranchSelectorProps = ComponentProps<typeof ButtonGroup>;\n\nexport const MessageBranchSelector = ({ className, ...props }: MessageBranchSelectorProps) => {\n  const { totalBranches } = useMessageBranch();\n\n  // Don\'t render if there\'s only one branch\n  if (totalBranches <= 1) {\n    return null;\n  }\n\n  return (\n    <ButtonGroup\n      className={cn(\n        "[&>*:not(:first-child)]:rounded-l-md [&>*:not(:last-child)]:rounded-r-md",\n        className,\n      )}\n      orientation="horizontal"\n      {...props}\n    />\n  );\n};\n\nexport type MessageBranchPreviousProps = ComponentProps<typeof Button>;\n\nexport const MessageBranchPrevious = ({ children, ...props }: MessageBranchPreviousProps) => {\n  const { goToPrevious, totalBranches } = useMessageBranch();\n\n  return (\n    <Button\n      aria-label="Previous branch"\n      disabled={totalBranches <= 1}\n      onClick={goToPrevious}\n      size="icon-sm"\n      type="button"\n      variant="ghost"\n      {...props}\n    >\n      {children ?? <ChevronLeftIcon size={14} />}\n    </Button>\n  );\n};\n\nexport type MessageBranchNextProps = ComponentProps<typeof Button>;\n\nexport const MessageBranchNext = ({ children, ...props }: MessageBranchNextProps) => {\n  const { goToNext, totalBranches } = useMessageBranch();\n\n  return (\n    <Button\n      aria-label="Next branch"\n      disabled={totalBranches <= 1}\n      onClick={goToNext}\n      size="icon-sm"\n      type="button"\n      variant="ghost"\n      {...props}\n    >\n      {children ?? <ChevronRightIcon size={14} />}\n    </Button>\n  );\n};\n\nexport type MessageBranchPageProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const MessageBranchPage = ({ className, ...props }: MessageBranchPageProps) => {\n  const { currentBranch, totalBranches } = useMessageBranch();\n\n  return (\n    <ButtonGroupText\n      className={cn("border-none bg-transparent text-muted-foreground shadow-none", className)}\n      {...props}\n    >\n      {currentBranch + 1} of {totalBranches}\n    </ButtonGroupText>\n  );\n};\n\nexport type MessageResponseProps = ComponentProps<typeof Streamdown>;\n\nconst streamdownPlugins = { cjk, code, math, mermaid };\n\nexport const MessageResponse = memo(\n  ({ className, ...props }: MessageResponseProps) => (\n    <Streamdown\n      className={cn("size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", className)}\n      plugins={streamdownPlugins}\n      {...props}\n    />\n  ),\n  (prevProps, nextProps) =>\n    prevProps.children === nextProps.children && nextProps.isAnimating === prevProps.isAnimating,\n);\n\nMessageResponse.displayName = "MessageResponse";\n\nexport type MessageToolbarProps = ComponentProps<"div">;\n\nexport const MessageToolbar = ({ className, children, ...props }: MessageToolbarProps) => (\n  <div className={cn("mt-4 flex w-full items-center justify-between gap-4", className)} {...props}>\n    {children}\n  </div>\n);\n';
    readonly "components/ai-elements/prompt-input.tsx": '"use client";\n\nimport {\n  Command,\n  CommandEmpty,\n  CommandGroup,\n  CommandInput,\n  CommandItem,\n  CommandList,\n  CommandSeparator,\n} from "@/components/ui/command";\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuTrigger,\n} from "@/components/ui/dropdown-menu";\nimport { HoverCard, HoverCardContent, HoverCardTrigger } from "@/components/ui/hover-card";\nimport {\n  InputGroup,\n  InputGroupAddon,\n  InputGroupButton,\n  InputGroupTextarea,\n} from "@/components/ui/input-group";\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue,\n} from "@/components/ui/select";\nimport { Spinner } from "@/components/ui/spinner";\nimport { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";\nimport { cn } from "@/lib/utils";\nimport type { ChatStatus, FileUIPart, SourceDocumentUIPart } from "ai";\nimport { ArrowUpIcon, ImageIcon, Monitor, PlusIcon, XIcon } from "lucide-react";\nimport { nanoid } from "nanoid";\nimport type {\n  ChangeEvent,\n  ChangeEventHandler,\n  ClipboardEventHandler,\n  ComponentProps,\n  FormEvent,\n  FormEventHandler,\n  HTMLAttributes,\n  KeyboardEventHandler,\n  PropsWithChildren,\n  ReactNode,\n  RefObject,\n} from "react";\nimport {\n  Children,\n  createContext,\n  useCallback,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n} from "react";\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nconst convertBlobUrlToDataUrl = async (url: string): Promise<string | null> => {\n  try {\n    const response = await fetch(url);\n    const blob = await response.blob();\n    // FileReader uses callback-based API, wrapping in Promise is necessary\n    // oxlint-disable-next-line eslint-plugin-promise(avoid-new)\n    return new Promise((resolve) => {\n      const reader = new FileReader();\n      // oxlint-disable-next-line eslint-plugin-unicorn(prefer-add-event-listener)\n      reader.onloadend = () => resolve(reader.result as string);\n      // oxlint-disable-next-line eslint-plugin-unicorn(prefer-add-event-listener)\n      reader.onerror = () => resolve(null);\n      reader.readAsDataURL(blob);\n    });\n  } catch {\n    return null;\n  }\n};\n\nconst captureScreenshot = async (): Promise<File | null> => {\n  if (typeof navigator === "undefined" || !navigator.mediaDevices?.getDisplayMedia) {\n    return null;\n  }\n\n  let stream: MediaStream | null = null;\n  const video = document.createElement("video");\n  video.muted = true;\n  video.playsInline = true;\n\n  try {\n    stream = await navigator.mediaDevices.getDisplayMedia({\n      audio: false,\n      video: true,\n    });\n\n    video.srcObject = stream;\n\n    // Video element uses callback-based API, wrapping in Promise is necessary\n    // oxlint-disable-next-line eslint-plugin-promise(avoid-new)\n    await new Promise<void>((resolve, reject) => {\n      // oxlint-disable-next-line eslint-plugin-unicorn(prefer-add-event-listener)\n      video.onloadedmetadata = () => resolve();\n      // oxlint-disable-next-line eslint-plugin-unicorn(prefer-add-event-listener)\n      video.onerror = () => reject(new Error("Failed to load screen stream"));\n    });\n\n    await video.play();\n\n    const width = video.videoWidth;\n    const height = video.videoHeight;\n    if (!width || !height) {\n      return null;\n    }\n\n    const canvas = document.createElement("canvas");\n    canvas.width = width;\n    canvas.height = height;\n    const context = canvas.getContext("2d");\n    if (!context) {\n      return null;\n    }\n\n    context.drawImage(video, 0, 0, width, height);\n    // canvas.toBlob uses callback-based API, wrapping in Promise is necessary\n    // oxlint-disable-next-line eslint-plugin-promise(avoid-new)\n    const blob = await new Promise<Blob | null>((resolve) => {\n      canvas.toBlob(resolve, "image/png");\n    });\n    if (!blob) {\n      return null;\n    }\n\n    const timestamp = new Date()\n      .toISOString()\n      .replaceAll(/[:.]/g, "-")\n      .replace("T", "_")\n      .replace("Z", "");\n\n    return new File([blob], `screenshot-${timestamp}.png`, {\n      lastModified: Date.now(),\n      type: "image/png",\n    });\n  } finally {\n    if (stream) {\n      for (const track of stream.getTracks()) {\n        track.stop();\n      }\n    }\n    video.pause();\n    video.srcObject = null;\n  }\n};\n\n// ============================================================================\n// Provider Context & Types\n// ============================================================================\n\nexport interface AttachmentsContext {\n  files: (FileUIPart & { id: string })[];\n  add: (files: File[] | FileList) => void;\n  remove: (id: string) => void;\n  clear: () => void;\n  openFileDialog: () => void;\n  fileInputRef: RefObject<HTMLInputElement | null>;\n}\n\nexport interface TextInputContext {\n  value: string;\n  setInput: (v: string) => void;\n  clear: () => void;\n}\n\nexport interface PromptInputControllerProps {\n  textInput: TextInputContext;\n  attachments: AttachmentsContext;\n  /** INTERNAL: Allows PromptInput to register its file textInput + "open" callback */\n  __registerFileInput: (ref: RefObject<HTMLInputElement | null>, open: () => void) => void;\n}\n\nconst PromptInputController = createContext<PromptInputControllerProps | null>(null);\nconst ProviderAttachmentsContext = createContext<AttachmentsContext | null>(null);\n\nexport const usePromptInputController = () => {\n  const ctx = useContext(PromptInputController);\n  if (!ctx) {\n    throw new Error(\n      "Wrap your component inside <PromptInputProvider> to use usePromptInputController().",\n    );\n  }\n  return ctx;\n};\n\n// Optional variants (do NOT throw). Useful for dual-mode components.\nconst useOptionalPromptInputController = () => useContext(PromptInputController);\n\nexport const useProviderAttachments = () => {\n  const ctx = useContext(ProviderAttachmentsContext);\n  if (!ctx) {\n    throw new Error(\n      "Wrap your component inside <PromptInputProvider> to use useProviderAttachments().",\n    );\n  }\n  return ctx;\n};\n\nconst useOptionalProviderAttachments = () => useContext(ProviderAttachmentsContext);\n\nexport type PromptInputProviderProps = PropsWithChildren<{\n  initialInput?: string;\n}>;\n\n/**\n * Optional global provider that lifts PromptInput state outside of PromptInput.\n * If you don\'t use it, PromptInput stays fully self-managed.\n */\nexport const PromptInputProvider = ({\n  initialInput: initialTextInput = "",\n  children,\n}: PromptInputProviderProps) => {\n  // ----- textInput state\n  const [textInput, setTextInput] = useState(initialTextInput);\n  const clearInput = useCallback(() => setTextInput(""), []);\n\n  // ----- attachments state (global when wrapped)\n  const [attachmentFiles, setAttachmentFiles] = useState<(FileUIPart & { id: string })[]>([]);\n  const fileInputRef = useRef<HTMLInputElement | null>(null);\n  // oxlint-disable-next-line eslint(no-empty-function)\n  const openRef = useRef<() => void>(() => {});\n\n  const add = useCallback((files: File[] | FileList) => {\n    const incoming = [...files];\n    if (incoming.length === 0) {\n      return;\n    }\n\n    setAttachmentFiles((prev) => [\n      ...prev,\n      ...incoming.map((file) => ({\n        filename: file.name,\n        id: nanoid(),\n        mediaType: file.type,\n        type: "file" as const,\n        url: URL.createObjectURL(file),\n      })),\n    ]);\n  }, []);\n\n  const remove = useCallback((id: string) => {\n    setAttachmentFiles((prev) => {\n      const found = prev.find((f) => f.id === id);\n      if (found?.url) {\n        URL.revokeObjectURL(found.url);\n      }\n      return prev.filter((f) => f.id !== id);\n    });\n  }, []);\n\n  const clear = useCallback(() => {\n    setAttachmentFiles((prev) => {\n      for (const f of prev) {\n        if (f.url) {\n          URL.revokeObjectURL(f.url);\n        }\n      }\n      return [];\n    });\n  }, []);\n\n  // Keep a ref to attachments for cleanup on unmount (avoids stale closure)\n  const attachmentsRef = useRef(attachmentFiles);\n\n  useEffect(() => {\n    attachmentsRef.current = attachmentFiles;\n  }, [attachmentFiles]);\n\n  // Cleanup blob URLs on unmount to prevent memory leaks\n  useEffect(\n    () => () => {\n      for (const f of attachmentsRef.current) {\n        if (f.url) {\n          URL.revokeObjectURL(f.url);\n        }\n      }\n    },\n    [],\n  );\n\n  const openFileDialog = useCallback(() => {\n    openRef.current?.();\n  }, []);\n\n  const attachments = useMemo<AttachmentsContext>(\n    () => ({\n      add,\n      clear,\n      fileInputRef,\n      files: attachmentFiles,\n      openFileDialog,\n      remove,\n    }),\n    [attachmentFiles, add, remove, clear, openFileDialog],\n  );\n\n  const __registerFileInput = useCallback(\n    (ref: RefObject<HTMLInputElement | null>, open: () => void) => {\n      fileInputRef.current = ref.current;\n      openRef.current = open;\n    },\n    [],\n  );\n\n  const controller = useMemo<PromptInputControllerProps>(\n    () => ({\n      __registerFileInput,\n      attachments,\n      textInput: {\n        clear: clearInput,\n        setInput: setTextInput,\n        value: textInput,\n      },\n    }),\n    [textInput, clearInput, attachments, __registerFileInput],\n  );\n\n  return (\n    <PromptInputController.Provider value={controller}>\n      <ProviderAttachmentsContext.Provider value={attachments}>\n        {children}\n      </ProviderAttachmentsContext.Provider>\n    </PromptInputController.Provider>\n  );\n};\n\n// ============================================================================\n// Component Context & Hooks\n// ============================================================================\n\nconst LocalAttachmentsContext = createContext<AttachmentsContext | null>(null);\n\nexport const usePromptInputAttachments = () => {\n  // Prefer local context (inside PromptInput) as it has validation, fall back to provider\n  const provider = useOptionalProviderAttachments();\n  const local = useContext(LocalAttachmentsContext);\n  const context = local ?? provider;\n  if (!context) {\n    throw new Error(\n      "usePromptInputAttachments must be used within a PromptInput or PromptInputProvider",\n    );\n  }\n  return context;\n};\n\n// ============================================================================\n// Referenced Sources (Local to PromptInput)\n// ============================================================================\n\nexport interface ReferencedSourcesContext {\n  sources: (SourceDocumentUIPart & { id: string })[];\n  add: (sources: SourceDocumentUIPart[] | SourceDocumentUIPart) => void;\n  remove: (id: string) => void;\n  clear: () => void;\n}\n\nexport const LocalReferencedSourcesContext = createContext<ReferencedSourcesContext | null>(null);\n\nexport const usePromptInputReferencedSources = () => {\n  const ctx = useContext(LocalReferencedSourcesContext);\n  if (!ctx) {\n    throw new Error(\n      "usePromptInputReferencedSources must be used within a LocalReferencedSourcesContext.Provider",\n    );\n  }\n  return ctx;\n};\n\nexport type PromptInputActionAddAttachmentsProps = ComponentProps<typeof DropdownMenuItem> & {\n  label?: string;\n};\n\nexport const PromptInputActionAddAttachments = ({\n  label = "Add photos or files",\n  ...props\n}: PromptInputActionAddAttachmentsProps) => {\n  const attachments = usePromptInputAttachments();\n\n  const handleSelect = useCallback(\n    (e: Event) => {\n      e.preventDefault();\n      attachments.openFileDialog();\n    },\n    [attachments],\n  );\n\n  return (\n    <DropdownMenuItem {...props} onSelect={handleSelect}>\n      <ImageIcon className="mr-2 size-4" /> {label}\n    </DropdownMenuItem>\n  );\n};\n\nexport type PromptInputActionAddScreenshotProps = ComponentProps<typeof DropdownMenuItem> & {\n  label?: string;\n};\n\nexport const PromptInputActionAddScreenshot = ({\n  label = "Take screenshot",\n  onSelect,\n  ...props\n}: PromptInputActionAddScreenshotProps) => {\n  const attachments = usePromptInputAttachments();\n\n  const handleSelect = useCallback(\n    async (event: Event) => {\n      onSelect?.(event);\n      if (event.defaultPrevented) {\n        return;\n      }\n\n      try {\n        const screenshot = await captureScreenshot();\n        if (screenshot) {\n          attachments.add([screenshot]);\n        }\n      } catch (error) {\n        if (\n          error instanceof DOMException &&\n          (error.name === "NotAllowedError" || error.name === "AbortError")\n        ) {\n          return;\n        }\n        throw error;\n      }\n    },\n    [onSelect, attachments],\n  );\n\n  return (\n    <DropdownMenuItem {...props} onSelect={handleSelect}>\n      <Monitor className="mr-2 size-4" />\n      {label}\n    </DropdownMenuItem>\n  );\n};\n\nexport interface PromptInputMessage {\n  text: string;\n  files: FileUIPart[];\n}\n\nexport type PromptInputProps = Omit<HTMLAttributes<HTMLFormElement>, "onSubmit" | "onError"> & {\n  // e.g., "image/*" or leave undefined for any\n  accept?: string;\n  multiple?: boolean;\n  // When true, accepts drops anywhere on document. Default false (opt-in).\n  globalDrop?: boolean;\n  // Render a hidden input with given name and keep it in sync for native form posts. Default false.\n  syncHiddenInput?: boolean;\n  // Minimal constraints\n  maxFiles?: number;\n  // bytes\n  maxFileSize?: number;\n  onError?: (err: { code: "max_files" | "max_file_size" | "accept"; message: string }) => void;\n  onSubmit: (\n    message: PromptInputMessage,\n    event: FormEvent<HTMLFormElement>,\n  ) => void | Promise<void>;\n};\n\nexport const PromptInput = ({\n  className,\n  accept,\n  multiple,\n  globalDrop,\n  syncHiddenInput,\n  maxFiles,\n  maxFileSize,\n  onError,\n  onSubmit,\n  children,\n  ...props\n}: PromptInputProps) => {\n  // Try to use a provider controller if present\n  const controller = useOptionalPromptInputController();\n  const usingProvider = !!controller;\n\n  // Refs\n  const inputRef = useRef<HTMLInputElement | null>(null);\n  const formRef = useRef<HTMLFormElement | null>(null);\n\n  // ----- Local attachments (only used when no provider)\n  const [items, setItems] = useState<(FileUIPart & { id: string })[]>([]);\n  const files = usingProvider ? controller.attachments.files : items;\n\n  // ----- Local referenced sources (always local to PromptInput)\n  const [referencedSources, setReferencedSources] = useState<\n    (SourceDocumentUIPart & { id: string })[]\n  >([]);\n\n  // Keep a ref to files for cleanup on unmount (avoids stale closure)\n  const filesRef = useRef(files);\n\n  useEffect(() => {\n    filesRef.current = files;\n  }, [files]);\n\n  const openFileDialogLocal = useCallback(() => {\n    inputRef.current?.click();\n  }, []);\n\n  const matchesAccept = useCallback(\n    (f: File) => {\n      if (!accept || accept.trim() === "") {\n        return true;\n      }\n\n      const patterns = accept\n        .split(",")\n        .map((s) => s.trim())\n        .filter(Boolean);\n\n      return patterns.some((pattern) => {\n        if (pattern.endsWith("/*")) {\n          // e.g: image/* -> image/\n          const prefix = pattern.slice(0, -1);\n          return f.type.startsWith(prefix);\n        }\n        return f.type === pattern;\n      });\n    },\n    [accept],\n  );\n\n  const addLocal = useCallback(\n    (fileList: File[] | FileList) => {\n      const incoming = [...fileList];\n      const accepted = incoming.filter((f) => matchesAccept(f));\n      if (incoming.length && accepted.length === 0) {\n        onError?.({\n          code: "accept",\n          message: "No files match the accepted types.",\n        });\n        return;\n      }\n      const withinSize = (f: File) => (maxFileSize ? f.size <= maxFileSize : true);\n      const sized = accepted.filter(withinSize);\n      if (accepted.length > 0 && sized.length === 0) {\n        onError?.({\n          code: "max_file_size",\n          message: "All files exceed the maximum size.",\n        });\n        return;\n      }\n\n      setItems((prev) => {\n        const capacity =\n          typeof maxFiles === "number" ? Math.max(0, maxFiles - prev.length) : undefined;\n        const capped = typeof capacity === "number" ? sized.slice(0, capacity) : sized;\n        if (typeof capacity === "number" && sized.length > capacity) {\n          onError?.({\n            code: "max_files",\n            message: "Too many files. Some were not added.",\n          });\n        }\n        const next: (FileUIPart & { id: string })[] = [];\n        for (const file of capped) {\n          next.push({\n            filename: file.name,\n            id: nanoid(),\n            mediaType: file.type,\n            type: "file",\n            url: URL.createObjectURL(file),\n          });\n        }\n        return [...prev, ...next];\n      });\n    },\n    [matchesAccept, maxFiles, maxFileSize, onError],\n  );\n\n  const removeLocal = useCallback(\n    (id: string) =>\n      setItems((prev) => {\n        const found = prev.find((file) => file.id === id);\n        if (found?.url) {\n          URL.revokeObjectURL(found.url);\n        }\n        return prev.filter((file) => file.id !== id);\n      }),\n    [],\n  );\n\n  // Wrapper that validates files before calling provider\'s add\n  const addWithProviderValidation = useCallback(\n    (fileList: File[] | FileList) => {\n      const incoming = [...fileList];\n      const accepted = incoming.filter((f) => matchesAccept(f));\n      if (incoming.length && accepted.length === 0) {\n        onError?.({\n          code: "accept",\n          message: "No files match the accepted types.",\n        });\n        return;\n      }\n      const withinSize = (f: File) => (maxFileSize ? f.size <= maxFileSize : true);\n      const sized = accepted.filter(withinSize);\n      if (accepted.length > 0 && sized.length === 0) {\n        onError?.({\n          code: "max_file_size",\n          message: "All files exceed the maximum size.",\n        });\n        return;\n      }\n\n      const currentCount = files.length;\n      const capacity =\n        typeof maxFiles === "number" ? Math.max(0, maxFiles - currentCount) : undefined;\n      const capped = typeof capacity === "number" ? sized.slice(0, capacity) : sized;\n      if (typeof capacity === "number" && sized.length > capacity) {\n        onError?.({\n          code: "max_files",\n          message: "Too many files. Some were not added.",\n        });\n      }\n\n      if (capped.length > 0) {\n        controller?.attachments.add(capped);\n      }\n    },\n    [matchesAccept, maxFileSize, maxFiles, onError, files.length, controller],\n  );\n\n  const clearAttachments = useCallback(\n    () =>\n      usingProvider\n        ? controller?.attachments.clear()\n        : setItems((prev) => {\n            for (const file of prev) {\n              if (file.url) {\n                URL.revokeObjectURL(file.url);\n              }\n            }\n            return [];\n          }),\n    [usingProvider, controller],\n  );\n\n  const clearReferencedSources = useCallback(() => setReferencedSources([]), []);\n\n  const add = usingProvider ? addWithProviderValidation : addLocal;\n  const remove = usingProvider ? controller.attachments.remove : removeLocal;\n  const openFileDialog = usingProvider\n    ? controller.attachments.openFileDialog\n    : openFileDialogLocal;\n\n  const clear = useCallback(() => {\n    clearAttachments();\n    clearReferencedSources();\n  }, [clearAttachments, clearReferencedSources]);\n\n  // Let provider know about our hidden file input so external menus can call openFileDialog()\n  useEffect(() => {\n    if (!usingProvider) {\n      return;\n    }\n    controller.__registerFileInput(inputRef, () => inputRef.current?.click());\n  }, [usingProvider, controller]);\n\n  // Note: File input cannot be programmatically set for security reasons\n  // The syncHiddenInput prop is no longer functional\n  useEffect(() => {\n    if (syncHiddenInput && inputRef.current && files.length === 0) {\n      inputRef.current.value = "";\n    }\n  }, [files, syncHiddenInput]);\n\n  // Attach drop handlers on nearest form and document (opt-in)\n  useEffect(() => {\n    const form = formRef.current;\n    if (!form) {\n      return;\n    }\n    if (globalDrop) {\n      // when global drop is on, let the document-level handler own drops\n      return;\n    }\n\n    const onDragOver = (e: DragEvent) => {\n      if (e.dataTransfer?.types?.includes("Files")) {\n        e.preventDefault();\n      }\n    };\n    const onDrop = (e: DragEvent) => {\n      if (e.dataTransfer?.types?.includes("Files")) {\n        e.preventDefault();\n      }\n      if (e.dataTransfer?.files && e.dataTransfer.files.length > 0) {\n        add(e.dataTransfer.files);\n      }\n    };\n    form.addEventListener("dragover", onDragOver);\n    form.addEventListener("drop", onDrop);\n    return () => {\n      form.removeEventListener("dragover", onDragOver);\n      form.removeEventListener("drop", onDrop);\n    };\n  }, [add, globalDrop]);\n\n  useEffect(() => {\n    if (!globalDrop) {\n      return;\n    }\n\n    const onDragOver = (e: DragEvent) => {\n      if (e.dataTransfer?.types?.includes("Files")) {\n        e.preventDefault();\n      }\n    };\n    const onDrop = (e: DragEvent) => {\n      if (e.dataTransfer?.types?.includes("Files")) {\n        e.preventDefault();\n      }\n      if (e.dataTransfer?.files && e.dataTransfer.files.length > 0) {\n        add(e.dataTransfer.files);\n      }\n    };\n    document.addEventListener("dragover", onDragOver);\n    document.addEventListener("drop", onDrop);\n    return () => {\n      document.removeEventListener("dragover", onDragOver);\n      document.removeEventListener("drop", onDrop);\n    };\n  }, [add, globalDrop]);\n\n  useEffect(\n    () => () => {\n      if (!usingProvider) {\n        for (const f of filesRef.current) {\n          if (f.url) {\n            URL.revokeObjectURL(f.url);\n          }\n        }\n      }\n    },\n    [usingProvider],\n  );\n\n  const handleChange: ChangeEventHandler<HTMLInputElement> = useCallback(\n    (event) => {\n      if (event.currentTarget.files) {\n        add(event.currentTarget.files);\n      }\n      // Reset input value to allow selecting files that were previously removed\n      event.currentTarget.value = "";\n    },\n    [add],\n  );\n\n  const attachmentsCtx = useMemo<AttachmentsContext>(\n    () => ({\n      add,\n      clear: clearAttachments,\n      fileInputRef: inputRef,\n      files: files.map((item) => ({ ...item, id: item.id })),\n      openFileDialog,\n      remove,\n    }),\n    [files, add, remove, clearAttachments, openFileDialog],\n  );\n\n  const refsCtx = useMemo<ReferencedSourcesContext>(\n    () => ({\n      add: (incoming: SourceDocumentUIPart[] | SourceDocumentUIPart) => {\n        const array = Array.isArray(incoming) ? incoming : [incoming];\n        setReferencedSources((prev) => [...prev, ...array.map((s) => ({ ...s, id: nanoid() }))]);\n      },\n      clear: clearReferencedSources,\n      remove: (id: string) => {\n        setReferencedSources((prev) => prev.filter((s) => s.id !== id));\n      },\n      sources: referencedSources,\n    }),\n    [referencedSources, clearReferencedSources],\n  );\n\n  const handleSubmit: FormEventHandler<HTMLFormElement> = useCallback(\n    async (event) => {\n      event.preventDefault();\n\n      const form = event.currentTarget;\n      const text = usingProvider\n        ? controller.textInput.value\n        : (() => {\n            const formData = new FormData(form);\n            return (formData.get("message") as string) || "";\n          })();\n\n      // Reset form immediately after capturing text to avoid race condition\n      // where user input during async blob conversion would be lost\n      if (!usingProvider) {\n        form.reset();\n      }\n\n      try {\n        // Convert blob URLs to data URLs asynchronously\n        const convertedFiles: FileUIPart[] = await Promise.all(\n          files.map(async ({ id: _id, ...item }) => {\n            if (item.url?.startsWith("blob:")) {\n              const dataUrl = await convertBlobUrlToDataUrl(item.url);\n              // If conversion failed, keep the original blob URL\n              return {\n                ...item,\n                url: dataUrl ?? item.url,\n              };\n            }\n            return item;\n          }),\n        );\n\n        const result = onSubmit({ files: convertedFiles, text }, event);\n\n        // Handle both sync and async onSubmit\n        if (result instanceof Promise) {\n          try {\n            await result;\n            clear();\n            if (usingProvider) {\n              controller.textInput.clear();\n            }\n          } catch {\n            // Don\'t clear on error - user may want to retry\n          }\n        } else {\n          // Sync function completed without throwing, clear inputs\n          clear();\n          if (usingProvider) {\n            controller.textInput.clear();\n          }\n        }\n      } catch {\n        // Don\'t clear on error - user may want to retry\n      }\n    },\n    [usingProvider, controller, files, onSubmit, clear],\n  );\n\n  // Render with or without local provider\n  const inner = (\n    <>\n      <input\n        accept={accept}\n        aria-label="Upload files"\n        className="hidden"\n        multiple={multiple}\n        onChange={handleChange}\n        ref={inputRef}\n        title="Upload files"\n        type="file"\n      />\n      <form className="w-full" onSubmit={handleSubmit} ref={formRef} {...props}>\n        <InputGroup\n          className={cn(\n            "overflow-hidden rounded-2xl bg-card/80 shadow-sm backdrop-blur-md",\n            "focus-within:border-foreground! has-[[data-slot=input-group-control]:focus-visible]:border-foreground!",\n            className,\n          )}\n        >\n          {children}\n        </InputGroup>\n      </form>\n    </>\n  );\n\n  const withReferencedSources = (\n    <LocalReferencedSourcesContext.Provider value={refsCtx}>\n      {inner}\n    </LocalReferencedSourcesContext.Provider>\n  );\n\n  // Always provide LocalAttachmentsContext so children get validated add function\n  return (\n    <LocalAttachmentsContext.Provider value={attachmentsCtx}>\n      {withReferencedSources}\n    </LocalAttachmentsContext.Provider>\n  );\n};\n\nexport type PromptInputBodyProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputBody = ({ className, ...props }: PromptInputBodyProps) => (\n  <div className={cn("contents", className)} {...props} />\n);\n\nexport type PromptInputTextareaProps = ComponentProps<typeof InputGroupTextarea>;\n\nexport const PromptInputTextarea = ({\n  onChange,\n  onKeyDown,\n  className,\n  placeholder = "What would you like to know?",\n  ...props\n}: PromptInputTextareaProps) => {\n  const controller = useOptionalPromptInputController();\n  const attachments = usePromptInputAttachments();\n  const [isComposing, setIsComposing] = useState(false);\n\n  const handleKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = useCallback(\n    (e) => {\n      // Call the external onKeyDown handler first\n      onKeyDown?.(e);\n\n      // If the external handler prevented default, don\'t run internal logic\n      if (e.defaultPrevented) {\n        return;\n      }\n\n      if (e.key === "Enter") {\n        if (isComposing || e.nativeEvent.isComposing) {\n          return;\n        }\n        if (e.shiftKey) {\n          return;\n        }\n        e.preventDefault();\n\n        // Check if the submit button is disabled before submitting\n        const { form } = e.currentTarget;\n        const submitButton = form?.querySelector(\n          \'button[type="submit"]\',\n        ) as HTMLButtonElement | null;\n        if (submitButton?.disabled) {\n          return;\n        }\n\n        form?.requestSubmit();\n      }\n\n      // Remove last attachment when Backspace is pressed and textarea is empty\n      if (e.key === "Backspace" && e.currentTarget.value === "" && attachments.files.length > 0) {\n        e.preventDefault();\n        const lastAttachment = attachments.files.at(-1);\n        if (lastAttachment) {\n          attachments.remove(lastAttachment.id);\n        }\n      }\n    },\n    [onKeyDown, isComposing, attachments],\n  );\n\n  const handlePaste: ClipboardEventHandler<HTMLTextAreaElement> = useCallback(\n    (event) => {\n      const items = event.clipboardData?.items;\n\n      if (!items) {\n        return;\n      }\n\n      const files: File[] = [];\n\n      for (const item of items) {\n        if (item.kind === "file") {\n          const file = item.getAsFile();\n          if (file) {\n            files.push(file);\n          }\n        }\n      }\n\n      if (files.length > 0) {\n        event.preventDefault();\n        attachments.add(files);\n      }\n    },\n    [attachments],\n  );\n\n  const handleCompositionEnd = useCallback(() => setIsComposing(false), []);\n  const handleCompositionStart = useCallback(() => setIsComposing(true), []);\n\n  const controlledProps = controller\n    ? {\n        onChange: (e: ChangeEvent<HTMLTextAreaElement>) => {\n          controller.textInput.setInput(e.currentTarget.value);\n          onChange?.(e);\n        },\n        value: controller.textInput.value,\n      }\n    : {\n        onChange,\n      };\n\n  return (\n    <InputGroupTextarea\n      className={cn("field-sizing-content max-h-48 min-h-18 text-sm!", className)}\n      name="message"\n      onCompositionEnd={handleCompositionEnd}\n      onCompositionStart={handleCompositionStart}\n      onKeyDown={handleKeyDown}\n      onPaste={handlePaste}\n      placeholder={placeholder}\n      {...props}\n      {...controlledProps}\n    />\n  );\n};\n\nexport type PromptInputHeaderProps = Omit<ComponentProps<typeof InputGroupAddon>, "align">;\n\nexport const PromptInputHeader = ({ className, ...props }: PromptInputHeaderProps) => (\n  <InputGroupAddon\n    align="block-end"\n    className={cn("order-first flex-wrap gap-1", className)}\n    {...props}\n  />\n);\n\nexport type PromptInputFooterProps = Omit<ComponentProps<typeof InputGroupAddon>, "align">;\n\nexport const PromptInputFooter = ({ className, ...props }: PromptInputFooterProps) => (\n  <InputGroupAddon\n    align="block-end"\n    className={cn("justify-between gap-1", className)}\n    {...props}\n  />\n);\n\nexport type PromptInputToolsProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputTools = ({ className, ...props }: PromptInputToolsProps) => (\n  <div className={cn("flex min-w-0 items-center gap-1", className)} {...props} />\n);\n\nexport type PromptInputButtonTooltip =\n  | string\n  | {\n      content: ReactNode;\n      shortcut?: string;\n      side?: ComponentProps<typeof TooltipContent>["side"];\n    };\n\nexport type PromptInputButtonProps = ComponentProps<typeof InputGroupButton> & {\n  tooltip?: PromptInputButtonTooltip;\n};\n\nexport const PromptInputButton = ({\n  variant = "ghost",\n  className,\n  size,\n  tooltip,\n  ...props\n}: PromptInputButtonProps) => {\n  const newSize = size ?? (Children.count(props.children) > 1 ? "sm" : "icon-sm");\n\n  const button = (\n    <InputGroupButton\n      className={cn(\n        "rounded-full",\n        variant === "outline" && "bg-card hover:bg-card dark:hover:bg-input/30",\n        className,\n      )}\n      size={newSize}\n      type="button"\n      variant={variant}\n      {...props}\n    />\n  );\n\n  if (!tooltip) {\n    return button;\n  }\n\n  const tooltipContent = typeof tooltip === "string" ? tooltip : tooltip.content;\n  const shortcut = typeof tooltip === "string" ? undefined : tooltip.shortcut;\n  const side = typeof tooltip === "string" ? "top" : (tooltip.side ?? "top");\n\n  return (\n    <Tooltip>\n      <TooltipTrigger asChild>{button}</TooltipTrigger>\n      <TooltipContent side={side}>\n        {tooltipContent}\n        {shortcut && <span className="ml-2 text-muted-foreground">{shortcut}</span>}\n      </TooltipContent>\n    </Tooltip>\n  );\n};\n\nexport type PromptInputActionMenuProps = ComponentProps<typeof DropdownMenu>;\nexport const PromptInputActionMenu = (props: PromptInputActionMenuProps) => (\n  <DropdownMenu {...props} />\n);\n\nexport type PromptInputActionMenuTriggerProps = PromptInputButtonProps;\n\nexport const PromptInputActionMenuTrigger = ({\n  className,\n  children,\n  ...props\n}: PromptInputActionMenuTriggerProps) => (\n  <DropdownMenuTrigger asChild>\n    <PromptInputButton className={className} {...props}>\n      {children ?? <PlusIcon className="size-4" />}\n    </PromptInputButton>\n  </DropdownMenuTrigger>\n);\n\nexport type PromptInputActionMenuContentProps = ComponentProps<typeof DropdownMenuContent>;\nexport const PromptInputActionMenuContent = ({\n  className,\n  ...props\n}: PromptInputActionMenuContentProps) => (\n  <DropdownMenuContent align="start" className={cn(className)} {...props} />\n);\n\nexport type PromptInputActionMenuItemProps = ComponentProps<typeof DropdownMenuItem>;\nexport const PromptInputActionMenuItem = ({\n  className,\n  ...props\n}: PromptInputActionMenuItemProps) => <DropdownMenuItem className={cn(className)} {...props} />;\n\n// Note: Actions that perform side-effects (like opening a file dialog)\n// are provided in opt-in modules (e.g., prompt-input-attachments).\n\nexport type PromptInputSubmitProps = ComponentProps<typeof InputGroupButton> & {\n  status?: ChatStatus;\n  onStop?: () => void;\n};\n\nexport const PromptInputSubmit = ({\n  className,\n  variant = "default",\n  size = "icon-sm",\n  status,\n  onStop,\n  onClick,\n  children,\n  ...props\n}: PromptInputSubmitProps) => {\n  const isGenerating = status === "submitted" || status === "streaming";\n\n  let Icon = <ArrowUpIcon className="size-4" />;\n\n  if (status === "submitted") {\n    Icon = <Spinner />;\n  } else if (status === "streaming") {\n    Icon = <span aria-hidden className="size-2.5 rounded-[2px] bg-current" />;\n  } else if (status === "error") {\n    Icon = <XIcon className="size-4" />;\n  }\n\n  const handleClick = useCallback(\n    (e: React.MouseEvent<HTMLButtonElement>) => {\n      if (isGenerating && onStop) {\n        e.preventDefault();\n        onStop();\n        return;\n      }\n      onClick?.(e);\n    },\n    [isGenerating, onStop, onClick],\n  );\n\n  return (\n    <InputGroupButton\n      aria-label={isGenerating ? "Stop" : "Submit"}\n      className={cn("absolute right-2.5 bottom-2.5 rounded-full", className)}\n      onClick={handleClick}\n      size={size}\n      type={isGenerating && onStop ? "button" : "submit"}\n      variant={variant}\n      {...props}\n    >\n      {children ?? Icon}\n    </InputGroupButton>\n  );\n};\n\nexport type PromptInputSelectProps = ComponentProps<typeof Select>;\n\nexport const PromptInputSelect = (props: PromptInputSelectProps) => <Select {...props} />;\n\nexport type PromptInputSelectTriggerProps = ComponentProps<typeof SelectTrigger>;\n\nexport const PromptInputSelectTrigger = ({\n  className,\n  ...props\n}: PromptInputSelectTriggerProps) => (\n  <SelectTrigger\n    className={cn(\n      "border-none bg-transparent font-medium text-muted-foreground shadow-none transition-colors",\n      "hover:bg-accent hover:text-foreground aria-expanded:bg-accent aria-expanded:text-foreground",\n      className,\n    )}\n    {...props}\n  />\n);\n\nexport type PromptInputSelectContentProps = ComponentProps<typeof SelectContent>;\n\nexport const PromptInputSelectContent = ({\n  className,\n  ...props\n}: PromptInputSelectContentProps) => <SelectContent className={cn(className)} {...props} />;\n\nexport type PromptInputSelectItemProps = ComponentProps<typeof SelectItem>;\n\nexport const PromptInputSelectItem = ({ className, ...props }: PromptInputSelectItemProps) => (\n  <SelectItem className={cn(className)} {...props} />\n);\n\nexport type PromptInputSelectValueProps = ComponentProps<typeof SelectValue>;\n\nexport const PromptInputSelectValue = ({ className, ...props }: PromptInputSelectValueProps) => (\n  <SelectValue className={cn(className)} {...props} />\n);\n\nexport type PromptInputHoverCardProps = ComponentProps<typeof HoverCard>;\n\nexport const PromptInputHoverCard = ({\n  openDelay = 0,\n  closeDelay = 0,\n  ...props\n}: PromptInputHoverCardProps) => (\n  <HoverCard closeDelay={closeDelay} openDelay={openDelay} {...props} />\n);\n\nexport type PromptInputHoverCardTriggerProps = ComponentProps<typeof HoverCardTrigger>;\n\nexport const PromptInputHoverCardTrigger = (props: PromptInputHoverCardTriggerProps) => (\n  <HoverCardTrigger {...props} />\n);\n\nexport type PromptInputHoverCardContentProps = ComponentProps<typeof HoverCardContent>;\n\nexport const PromptInputHoverCardContent = ({\n  align = "start",\n  ...props\n}: PromptInputHoverCardContentProps) => <HoverCardContent align={align} {...props} />;\n\nexport type PromptInputTabsListProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputTabsList = ({ className, ...props }: PromptInputTabsListProps) => (\n  <div className={cn(className)} {...props} />\n);\n\nexport type PromptInputTabProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputTab = ({ className, ...props }: PromptInputTabProps) => (\n  <div className={cn(className)} {...props} />\n);\n\nexport type PromptInputTabLabelProps = HTMLAttributes<HTMLHeadingElement>;\n\nexport const PromptInputTabLabel = ({ className, ...props }: PromptInputTabLabelProps) => (\n  // Content provided via children in props\n  // oxlint-disable-next-line eslint-plugin-jsx-a11y(heading-has-content)\n  <h3 className={cn("mb-2 px-3 font-medium text-muted-foreground text-xs", className)} {...props} />\n);\n\nexport type PromptInputTabBodyProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputTabBody = ({ className, ...props }: PromptInputTabBodyProps) => (\n  <div className={cn("space-y-1", className)} {...props} />\n);\n\nexport type PromptInputTabItemProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputTabItem = ({ className, ...props }: PromptInputTabItemProps) => (\n  <div\n    className={cn("flex items-center gap-2 px-3 py-2 text-xs hover:bg-accent", className)}\n    {...props}\n  />\n);\n\nexport type PromptInputCommandProps = ComponentProps<typeof Command>;\n\nexport const PromptInputCommand = ({ className, ...props }: PromptInputCommandProps) => (\n  <Command className={cn(className)} {...props} />\n);\n\nexport type PromptInputCommandInputProps = ComponentProps<typeof CommandInput>;\n\nexport const PromptInputCommandInput = ({ className, ...props }: PromptInputCommandInputProps) => (\n  <CommandInput className={cn(className)} {...props} />\n);\n\nexport type PromptInputCommandListProps = ComponentProps<typeof CommandList>;\n\nexport const PromptInputCommandList = ({ className, ...props }: PromptInputCommandListProps) => (\n  <CommandList className={cn(className)} {...props} />\n);\n\nexport type PromptInputCommandEmptyProps = ComponentProps<typeof CommandEmpty>;\n\nexport const PromptInputCommandEmpty = ({ className, ...props }: PromptInputCommandEmptyProps) => (\n  <CommandEmpty className={cn(className)} {...props} />\n);\n\nexport type PromptInputCommandGroupProps = ComponentProps<typeof CommandGroup>;\n\nexport const PromptInputCommandGroup = ({ className, ...props }: PromptInputCommandGroupProps) => (\n  <CommandGroup className={cn(className)} {...props} />\n);\n\nexport type PromptInputCommandItemProps = ComponentProps<typeof CommandItem>;\n\nexport const PromptInputCommandItem = ({ className, ...props }: PromptInputCommandItemProps) => (\n  <CommandItem className={cn(className)} {...props} />\n);\n\nexport type PromptInputCommandSeparatorProps = ComponentProps<typeof CommandSeparator>;\n\nexport const PromptInputCommandSeparator = ({\n  className,\n  ...props\n}: PromptInputCommandSeparatorProps) => <CommandSeparator className={cn(className)} {...props} />;\n';
    readonly "components/ai-elements/question.tsx": '"use client";\n\nimport type {\n  ChangeEvent,\n  ComponentProps,\n  FormEvent,\n  HTMLAttributes,\n  KeyboardEvent,\n  MouseEvent,\n  ReactNode,\n} from "react";\n\nimport { Button } from "@/components/ui/button";\nimport { Textarea } from "@/components/ui/textarea";\nimport { cn } from "@/lib/utils";\nimport { createContext, useCallback, useContext, useMemo, useState } from "react";\n\nexport interface QuestionValue {\n  selectedValues: readonly string[];\n  text: string;\n}\n\nexport interface QuestionResponse {\n  selectedValues: readonly string[];\n  text?: string;\n}\n\ntype SelectionMode = "multiple" | "single";\n\ninterface QuestionContextValue {\n  disabled: boolean;\n  selectedValues: readonly string[];\n  selectionMode: SelectionMode;\n  setText: (text: string) => void;\n  text: string;\n  toggleValue: (value: string) => void;\n}\n\nconst QuestionContext = createContext<QuestionContextValue | null>(null);\n\nconst useQuestion = () => {\n  const context = useContext(QuestionContext);\n\n  if (!context) {\n    throw new Error("Question components must be used within Question");\n  }\n\n  return context;\n};\n\nexport type QuestionProps = Omit<ComponentProps<"form">, "defaultValue" | "onSubmit" | "value"> & {\n  defaultValue?: QuestionValue;\n  disabled?: boolean;\n  onSubmit?: (\n    response: QuestionResponse,\n    event: FormEvent<HTMLFormElement>,\n  ) => void | Promise<void>;\n  onValueChange?: (value: QuestionValue) => void;\n  selectionMode?: SelectionMode;\n  value?: QuestionValue;\n};\n\nconst EMPTY_VALUE: QuestionValue = { selectedValues: [], text: "" };\n\nconst getSelectedValues = (\n  currentValues: readonly string[],\n  optionValue: string,\n  selectionMode: SelectionMode,\n): readonly string[] => {\n  const isSelected = currentValues.includes(optionValue);\n\n  if (selectionMode === "single") {\n    return isSelected ? [] : [optionValue];\n  }\n\n  if (isSelected) {\n    return currentValues.filter((item) => item !== optionValue);\n  }\n\n  return [...currentValues, optionValue];\n};\n\nexport const Question = ({\n  children,\n  className,\n  defaultValue = EMPTY_VALUE,\n  disabled = false,\n  onSubmit,\n  onValueChange,\n  selectionMode = "single",\n  value: controlledValue,\n  ...props\n}: QuestionProps) => {\n  const [internalValue, setInternalValue] = useState(defaultValue);\n  const value = controlledValue ?? internalValue;\n\n  const setValue = useCallback(\n    (nextValue: QuestionValue) => {\n      if (controlledValue === undefined) {\n        setInternalValue(nextValue);\n      }\n      onValueChange?.(nextValue);\n    },\n    [controlledValue, onValueChange],\n  );\n\n  const setText = useCallback(\n    (text: string) => {\n      setValue({ ...value, text });\n    },\n    [setValue, value],\n  );\n\n  const toggleValue = useCallback(\n    (optionValue: string) => {\n      const selectedValues = getSelectedValues(value.selectedValues, optionValue, selectionMode);\n      setValue({ ...value, selectedValues });\n    },\n    [selectionMode, setValue, value],\n  );\n\n  const contextValue = useMemo(\n    () => ({\n      disabled,\n      selectedValues: value.selectedValues,\n      selectionMode,\n      setText,\n      text: value.text,\n      toggleValue,\n    }),\n    [disabled, selectionMode, setText, toggleValue, value],\n  );\n\n  const handleSubmit = useCallback(\n    async (event: FormEvent<HTMLFormElement>) => {\n      event.preventDefault();\n      if (disabled) {\n        return;\n      }\n\n      const text = value.text.trim();\n      if (value.selectedValues.length === 0 && text.length === 0) {\n        return;\n      }\n\n      await onSubmit?.(\n        {\n          selectedValues: value.selectedValues,\n          text: text.length > 0 ? text : undefined,\n        },\n        event,\n      );\n    },\n    [disabled, onSubmit, value],\n  );\n\n  return (\n    <QuestionContext.Provider value={contextValue}>\n      <form\n        className={cn("space-y-3 rounded-xl border bg-card p-4", className)}\n        onSubmit={handleSubmit}\n        {...props}\n      >\n        {children}\n      </form>\n    </QuestionContext.Provider>\n  );\n};\n\nexport type QuestionPromptProps = HTMLAttributes<HTMLParagraphElement>;\n\nexport const QuestionPrompt = ({ className, ...props }: QuestionPromptProps) => (\n  <p className={cn("font-medium text-sm leading-snug", className)} {...props} />\n);\n\nexport type QuestionDescriptionProps = HTMLAttributes<HTMLParagraphElement>;\n\nexport const QuestionDescription = ({ className, ...props }: QuestionDescriptionProps) => (\n  <p className={cn("text-muted-foreground text-sm", className)} {...props} />\n);\n\nexport type QuestionOptionsProps = HTMLAttributes<HTMLDivElement>;\n\nexport const QuestionOptions = ({ className, ...props }: QuestionOptionsProps) => {\n  const { selectionMode } = useQuestion();\n\n  return (\n    <div\n      className={cn("flex flex-wrap gap-1.5", className)}\n      role={selectionMode === "single" ? "radiogroup" : "group"}\n      {...props}\n    />\n  );\n};\n\nexport type QuestionOptionProps = Omit<ComponentProps<typeof Button>, "value"> & {\n  value: string;\n};\n\nexport const QuestionOption = ({\n  children,\n  className,\n  disabled,\n  onClick,\n  value,\n  variant,\n  ...props\n}: QuestionOptionProps) => {\n  const question = useQuestion();\n  const isSelected = question.selectedValues.includes(value);\n  const role = question.selectionMode === "single" ? "radio" : "checkbox";\n  const handleClick = useCallback(\n    (event: MouseEvent<HTMLButtonElement>) => {\n      question.toggleValue(value);\n      onClick?.(event);\n    },\n    [onClick, question, value],\n  );\n\n  return (\n    <Button\n      aria-checked={isSelected}\n      // Selection only changes colors: the border is always present so the\n      // layout never shifts when an option is picked.\n      className={cn(\n        "group/option h-auto whitespace-normal border border-input font-normal shadow-none transition-colors",\n        isSelected\n          ? "border-foreground/20 bg-accent text-accent-foreground disabled:opacity-100"\n          : "text-muted-foreground hover:bg-accent/50 hover:text-foreground",\n        className,\n      )}\n      data-state={isSelected ? "checked" : "unchecked"}\n      disabled={question.disabled || disabled}\n      onClick={handleClick}\n      role={role}\n      type="button"\n      variant={variant ?? "ghost"}\n      {...props}\n    >\n      {children ?? value}\n    </Button>\n  );\n};\n\nexport type QuestionInputProps = Omit<ComponentProps<typeof Textarea>, "defaultValue" | "value">;\n\nexport const QuestionInput = ({\n  className,\n  disabled,\n  onChange,\n  onKeyDown,\n  ...props\n}: QuestionInputProps) => {\n  const question = useQuestion();\n  const handleChange = useCallback(\n    (event: ChangeEvent<HTMLTextAreaElement>) => {\n      question.setText(event.currentTarget.value);\n      onChange?.(event);\n    },\n    [onChange, question],\n  );\n  const handleKeyDown = useCallback(\n    (event: KeyboardEvent<HTMLTextAreaElement>) => {\n      onKeyDown?.(event);\n      if (\n        event.defaultPrevented ||\n        event.key !== "Enter" ||\n        event.shiftKey ||\n        event.nativeEvent.isComposing\n      ) {\n        return;\n      }\n\n      event.preventDefault();\n      event.currentTarget.form?.requestSubmit();\n    },\n    [onKeyDown],\n  );\n\n  return (\n    <Textarea\n      className={cn(\n        "min-h-16 resize-none rounded-lg text-sm shadow-none focus-visible:border-foreground!",\n        className,\n      )}\n      disabled={question.disabled || disabled}\n      onChange={handleChange}\n      onKeyDown={handleKeyDown}\n      value={question.text}\n      {...props}\n    />\n  );\n};\n\nexport type QuestionActionsProps = HTMLAttributes<HTMLDivElement>;\n\nexport const QuestionActions = ({ className, ...props }: QuestionActionsProps) => (\n  <div className={cn("flex items-center justify-end gap-2", className)} {...props} />\n);\n\nexport type QuestionSubmitProps = ComponentProps<typeof Button> & {\n  children?: ReactNode;\n};\n\nexport const QuestionSubmit = ({\n  children = "Submit",\n  className,\n  disabled,\n  size = "sm",\n  ...props\n}: QuestionSubmitProps) => {\n  const question = useQuestion();\n  const hasResponse = question.selectedValues.length > 0 || question.text.trim().length > 0;\n\n  return (\n    <Button\n      className={cn("text-sm! shadow-none", className)}\n      disabled={question.disabled || disabled || !hasResponse}\n      size={size}\n      type="submit"\n      {...props}\n    >\n      {children}\n    </Button>\n  );\n};\n';
    readonly "components/ai-elements/reasoning.tsx": '"use client";\n\nimport { useControllableState } from "@radix-ui/react-use-controllable-state";\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";\nimport { cn } from "@/lib/utils";\nimport { cjk } from "@streamdown/cjk";\nimport { code } from "@streamdown/code";\nimport { math } from "@streamdown/math";\nimport { mermaid } from "@streamdown/mermaid";\nimport { BrainIcon, ChevronDownIcon } from "lucide-react";\nimport type { ComponentProps, ReactNode } from "react";\nimport {\n  createContext,\n  memo,\n  useCallback,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n} from "react";\nimport { Streamdown } from "streamdown";\n\nimport { Shimmer } from "./shimmer";\n\ninterface ReasoningContextValue {\n  isStreaming: boolean;\n  isOpen: boolean;\n  setIsOpen: (open: boolean) => void;\n  duration: number | undefined;\n}\n\nconst ReasoningContext = createContext<ReasoningContextValue | null>(null);\n\nexport const useReasoning = () => {\n  const context = useContext(ReasoningContext);\n  if (!context) {\n    throw new Error("Reasoning components must be used within Reasoning");\n  }\n  return context;\n};\n\nexport type ReasoningProps = ComponentProps<typeof Collapsible> & {\n  isStreaming?: boolean;\n  open?: boolean;\n  defaultOpen?: boolean;\n  onOpenChange?: (open: boolean) => void;\n  duration?: number;\n};\n\nconst MS_IN_S = 1000;\n\nexport const Reasoning = memo(\n  ({\n    className,\n    isStreaming = false,\n    open,\n    defaultOpen,\n    onOpenChange,\n    duration: durationProp,\n    children,\n    ...props\n  }: ReasoningProps) => {\n    const resolvedDefaultOpen = defaultOpen ?? isStreaming;\n    // Track if defaultOpen was explicitly set to false (to prevent auto-open)\n    const isExplicitlyClosed = defaultOpen === false;\n\n    const [isOpen, setIsOpen] = useControllableState<boolean>({\n      defaultProp: resolvedDefaultOpen,\n      onChange: onOpenChange,\n      prop: open,\n    });\n    const [duration, setDuration] = useControllableState<number | undefined>({\n      defaultProp: undefined,\n      prop: durationProp,\n    });\n\n    const hasEverStreamedRef = useRef(isStreaming);\n    const [hasAutoClosed, setHasAutoClosed] = useState(false);\n    const startTimeRef = useRef<number | null>(null);\n\n    // Track when streaming starts and compute duration\n    useEffect(() => {\n      if (isStreaming) {\n        hasEverStreamedRef.current = true;\n        if (startTimeRef.current === null) {\n          startTimeRef.current = Date.now();\n        }\n      } else if (startTimeRef.current !== null) {\n        setDuration(Math.ceil((Date.now() - startTimeRef.current) / MS_IN_S));\n        startTimeRef.current = null;\n      }\n    }, [isStreaming, setDuration]);\n\n    // Auto-open when streaming starts (unless explicitly closed)\n    useEffect(() => {\n      if (isStreaming && !isOpen && !isExplicitlyClosed) {\n        setIsOpen(true);\n      }\n    }, [isStreaming, isOpen, setIsOpen, isExplicitlyClosed]);\n\n    // Auto-close when streaming ends (once only, and only if it ever streamed)\n    useEffect(() => {\n      if (hasEverStreamedRef.current && !isStreaming && isOpen && !hasAutoClosed) {\n        setIsOpen(false);\n        setHasAutoClosed(true);\n      }\n    }, [isStreaming, isOpen, setIsOpen, hasAutoClosed]);\n\n    const handleOpenChange = useCallback(\n      (newOpen: boolean) => {\n        setIsOpen(newOpen);\n      },\n      [setIsOpen],\n    );\n\n    const contextValue = useMemo(\n      () => ({ duration, isOpen, isStreaming, setIsOpen }),\n      [duration, isOpen, isStreaming, setIsOpen],\n    );\n\n    return (\n      <ReasoningContext.Provider value={contextValue}>\n        <Collapsible\n          className={cn("not-prose mb-4 w-full", className)}\n          onOpenChange={handleOpenChange}\n          open={isOpen}\n          {...props}\n        >\n          {children}\n        </Collapsible>\n      </ReasoningContext.Provider>\n    );\n  },\n);\n\nexport type ReasoningTriggerProps = ComponentProps<typeof CollapsibleTrigger> & {\n  getThinkingMessage?: (isStreaming: boolean, duration?: number) => ReactNode;\n};\n\nconst defaultGetThinkingMessage = (isStreaming: boolean, duration?: number) => {\n  if (isStreaming || duration === 0) {\n    return <Shimmer duration={1}>Thinking...</Shimmer>;\n  }\n  if (duration === undefined) {\n    return <p>Thought for a few seconds</p>;\n  }\n  return <p>Thought for {duration} seconds</p>;\n};\n\nexport const ReasoningTrigger = memo(\n  ({\n    className,\n    children,\n    getThinkingMessage = defaultGetThinkingMessage,\n    ...props\n  }: ReasoningTriggerProps) => {\n    const { isStreaming, isOpen, duration } = useReasoning();\n\n    return (\n      <CollapsibleTrigger\n        className={cn(\n          "flex w-full items-center gap-2 text-muted-foreground text-sm transition-colors hover:text-foreground",\n          className,\n        )}\n        {...props}\n      >\n        {children ?? (\n          <>\n            <BrainIcon className="size-4" />\n            {getThinkingMessage(isStreaming, duration)}\n            <ChevronDownIcon\n              className={cn("size-4 transition-transform", isOpen ? "rotate-180" : "rotate-0")}\n            />\n          </>\n        )}\n      </CollapsibleTrigger>\n    );\n  },\n);\n\nexport type ReasoningContentProps = ComponentProps<typeof CollapsibleContent> & {\n  children: string;\n};\n\nconst streamdownPlugins = { cjk, code, math, mermaid };\n\nexport const ReasoningContent = memo(({ className, children, ...props }: ReasoningContentProps) => (\n  <CollapsibleContent\n    className={cn(\n      "mt-4 text-sm",\n      "data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-muted-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",\n      className,\n    )}\n    {...props}\n  >\n    <Streamdown plugins={streamdownPlugins}>{children}</Streamdown>\n  </CollapsibleContent>\n));\n\nReasoning.displayName = "Reasoning";\nReasoningTrigger.displayName = "ReasoningTrigger";\nReasoningContent.displayName = "ReasoningContent";\n';
    readonly "components/ai-elements/shimmer.tsx": '"use client";\n\nimport { cn } from "@/lib/utils";\nimport type { MotionProps } from "motion/react";\nimport { motion } from "motion/react";\nimport type { CSSProperties, ElementType, JSX } from "react";\nimport { memo, useMemo } from "react";\n\ntype MotionHTMLProps = MotionProps & Record<string, unknown>;\n\n// Cache motion components at module level to avoid creating during render\nconst motionComponentCache = new Map<\n  keyof JSX.IntrinsicElements,\n  React.ComponentType<MotionHTMLProps>\n>();\n\nconst getMotionComponent = (element: keyof JSX.IntrinsicElements) => {\n  let component = motionComponentCache.get(element);\n  if (!component) {\n    component = motion.create(element);\n    motionComponentCache.set(element, component);\n  }\n  return component;\n};\n\nexport interface TextShimmerProps {\n  children: string;\n  as?: ElementType;\n  className?: string;\n  duration?: number;\n  spread?: number;\n}\n\nconst ShimmerComponent = ({\n  children,\n  as: Component = "p",\n  className,\n  duration = 2,\n  spread = 2,\n}: TextShimmerProps) => {\n  const MotionComponent = getMotionComponent(Component as keyof JSX.IntrinsicElements);\n\n  const dynamicSpread = useMemo(() => (children?.length ?? 0) * spread, [children, spread]);\n\n  return (\n    <MotionComponent\n      animate={{ backgroundPosition: "0% center" }}\n      className={cn(\n        "relative inline-block bg-[length:250%_100%,auto] bg-clip-text text-transparent",\n        "[--bg:linear-gradient(90deg,#0000_calc(50%-var(--spread)),var(--color-background),#0000_calc(50%+var(--spread)))] [background-repeat:no-repeat,padding-box]",\n        className,\n      )}\n      initial={{ backgroundPosition: "100% center" }}\n      style={\n        {\n          "--spread": `${dynamicSpread}px`,\n          backgroundImage:\n            "var(--bg), linear-gradient(var(--color-muted-foreground), var(--color-muted-foreground))",\n        } as CSSProperties\n      }\n      transition={{\n        duration,\n        ease: "linear",\n        repeat: Number.POSITIVE_INFINITY,\n      }}\n    >\n      {children}\n    </MotionComponent>\n  );\n};\n\nexport const Shimmer = memo(ShimmerComponent);\n';
    readonly "components/ai-elements/tool.tsx": '"use client";\n\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";\nimport { cn } from "@/lib/utils";\nimport type { DynamicToolUIPart, ToolUIPart } from "ai";\nimport { ChevronRightIcon, TerminalIcon, WrenchIcon } from "lucide-react";\nimport type { ComponentProps, ReactNode } from "react";\nimport { isValidElement } from "react";\n\nimport { CodeBlock } from "./code-block";\n\nconst compactCodeBlockClassName =\n  "rounded-none border-0 bg-transparent [&_pre]:!bg-transparent [&_pre]:px-3 [&_pre]:pt-2 [&_pre]:pb-3 [&_pre]:text-xs [&_code]:text-xs";\n\nexport type ToolProps = ComponentProps<typeof Collapsible>;\n\nexport const Tool = ({ className, ...props }: ToolProps) => (\n  <Collapsible className={cn("group not-prose w-full", className)} {...props} />\n);\n\nexport type ToolPart = ToolUIPart | DynamicToolUIPart;\n\nexport type ToolHeaderProps = {\n  title?: string;\n  className?: string;\n} & (\n  | { type: ToolUIPart["type"]; state: ToolUIPart["state"]; toolName?: never }\n  | {\n      type: DynamicToolUIPart["type"];\n      state: DynamicToolUIPart["state"];\n      toolName: string;\n    }\n);\n\nconst statusLabels: Record<ToolPart["state"], string> = {\n  "approval-requested": "Awaiting Approval",\n  "approval-responded": "Responded",\n  "input-available": "Running",\n  "input-streaming": "Pending",\n  "output-available": "Completed",\n  "output-denied": "Denied",\n  "output-error": "Error",\n};\n\nexport const getStatusIndicator = (status: ToolPart["state"]) =>\n  status === "output-available" ? null : (\n    <span className={cn("text-sm", status === "output-error" && "text-destructive")}>\n      {statusLabels[status]}\n    </span>\n  );\n\nexport const ToolHeader = ({\n  className,\n  title,\n  type,\n  state,\n  toolName,\n  ...props\n}: ToolHeaderProps) => {\n  const derivedName = type === "dynamic-tool" ? toolName : type.split("-").slice(1).join("-");\n  const displayName = title ?? derivedName;\n\n  return (\n    <CollapsibleTrigger\n      className={cn(\n        "flex w-full items-center gap-2 py-0.5 text-left text-muted-foreground transition-colors hover:text-foreground",\n        className,\n      )}\n      {...props}\n    >\n      {displayName === "bash" ? (\n        <TerminalIcon className="size-4 shrink-0" />\n      ) : (\n        <WrenchIcon className="size-4 shrink-0" />\n      )}\n      <span className="text-sm">{displayName}</span>\n      {getStatusIndicator(state)}\n      <ChevronRightIcon className="size-3.5 shrink-0 transition-transform group-data-[state=open]:rotate-90" />\n    </CollapsibleTrigger>\n  );\n};\n\nexport type ToolContentProps = ComponentProps<typeof CollapsibleContent>;\n\nexport const ToolContent = ({ className, ...props }: ToolContentProps) => (\n  <CollapsibleContent\n    className={cn(\n      "data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 space-y-4 py-2 text-popover-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",\n      className,\n    )}\n    {...props}\n  />\n);\n\nexport type BashToolContentProps = ComponentProps<"div"> & {\n  input: ToolPart["input"];\n  output: ToolPart["output"];\n  errorText: ToolPart["errorText"];\n};\n\nexport const BashToolContent = ({\n  className,\n  input,\n  output,\n  errorText,\n  ...props\n}: BashToolContentProps) => {\n  const command = getRecordValue(input, "command");\n  const stdout = getRecordValue(output, "stdout") ?? (typeof output === "string" ? output : "");\n  const stderr = getRecordValue(output, "stderr") ?? errorText ?? "";\n  const exitCode = getRecordValue(output, "exitCode");\n  const hasResult = Boolean(stdout || stderr || (typeof exitCode === "number" && exitCode !== 0));\n\n  return (\n    <div className={cn("space-y-2", className)} {...props}>\n      <pre className="overflow-x-auto whitespace-pre-wrap rounded-md bg-muted/50 p-3 font-mono text-xs leading-relaxed">\n        <code>\n          <span className="text-muted-foreground">$ </span>\n          {command ?? "…"}\n        </code>\n      </pre>\n      {hasResult ? (\n        <pre className="overflow-x-auto whitespace-pre-wrap rounded-md bg-muted/50 p-3 font-mono text-xs leading-relaxed">\n          <code>\n            <span className="mb-2 block font-sans text-[10px] text-muted-foreground uppercase tracking-wide">\n              Output\n            </span>\n            {stdout ? <span className="block">{String(stdout).trimEnd()}</span> : null}\n            {stderr ? (\n              <span className="block text-destructive">{String(stderr).trimEnd()}</span>\n            ) : null}\n            {typeof exitCode === "number" && exitCode !== 0 ? (\n              <span className="block text-muted-foreground">Exited with code {exitCode}</span>\n            ) : null}\n          </code>\n        </pre>\n      ) : null}\n    </div>\n  );\n};\n\nconst getRecordValue = (value: unknown, key: string): string | number | undefined => {\n  if (typeof value !== "object" || value === null || !(key in value)) {\n    return undefined;\n  }\n\n  const property = value[key as keyof typeof value];\n  return typeof property === "string" || typeof property === "number" ? property : undefined;\n};\n\nexport type ToolInputProps = ComponentProps<"div"> & {\n  input: ToolPart["input"];\n};\n\nexport const ToolInput = ({ className, input, ...props }: ToolInputProps) => (\n  <div className={cn("overflow-hidden rounded-md bg-muted/50", className)} {...props}>\n    <span className="block px-3 pt-3 font-sans text-[10px] text-muted-foreground uppercase tracking-wide">\n      Parameters\n    </span>\n    <div>\n      <CodeBlock\n        className={compactCodeBlockClassName}\n        code={JSON.stringify(input, null, 2)}\n        language="json"\n      />\n    </div>\n  </div>\n);\n\nexport type ToolOutputProps = ComponentProps<"div"> & {\n  output: ToolPart["output"];\n  errorText: ToolPart["errorText"];\n};\n\nexport const ToolOutput = ({ className, output, errorText, ...props }: ToolOutputProps) => {\n  if (!(output || errorText)) {\n    return null;\n  }\n\n  let Output = <div>{output as ReactNode}</div>;\n\n  if (typeof output === "object" && !isValidElement(output)) {\n    Output = (\n      <CodeBlock\n        className={compactCodeBlockClassName}\n        code={JSON.stringify(output, null, 2)}\n        language="json"\n      />\n    );\n  } else if (typeof output === "string") {\n    Output = <CodeBlock className={compactCodeBlockClassName} code={output} language="json" />;\n  }\n\n  return (\n    <div\n      className={cn(\n        "overflow-x-auto rounded-md text-xs [&_table]:w-full",\n        errorText ? "bg-destructive/10 text-destructive" : "bg-muted/50 text-foreground",\n        className,\n      )}\n      {...props}\n    >\n      <span className="block px-3 pt-3 font-sans text-[10px] text-muted-foreground uppercase tracking-wide">\n        {errorText ? "Error" : "Result"}\n      </span>\n      {errorText && <div className="px-3 pt-2 pb-3">{errorText}</div>}\n      {Output}\n    </div>\n  );\n};\n';
    readonly "components/ui/badge.tsx": 'import * as React from "react";\nimport { cva, type VariantProps } from "class-variance-authority";\nimport { Slot } from "radix-ui";\n\nimport { cn } from "@/lib/utils";\n\nconst badgeVariants = cva(\n  "inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3",\n  {\n    variants: {\n      variant: {\n        default: "bg-primary text-primary-foreground [a&]:hover:bg-primary/90",\n        secondary: "bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",\n        destructive:\n          "bg-destructive text-white focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/90",\n        outline:\n          "border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",\n        ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground",\n        link: "text-primary underline-offset-4 [a&]:hover:underline",\n      },\n    },\n    defaultVariants: {\n      variant: "default",\n    },\n  },\n);\n\nfunction Badge({\n  className,\n  variant = "default",\n  asChild = false,\n  ...props\n}: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & { asChild?: boolean }) {\n  const Comp = asChild ? Slot.Root : "span";\n\n  return (\n    <Comp\n      data-slot="badge"\n      data-variant={variant}\n      className={cn(badgeVariants({ variant }), className)}\n      {...props}\n    />\n  );\n}\n\nexport { Badge, badgeVariants };\n';
    readonly "components/ui/button-group.tsx": 'import { cva, type VariantProps } from "class-variance-authority";\nimport { Slot } from "radix-ui";\n\nimport { cn } from "@/lib/utils";\nimport { Separator } from "@/components/ui/separator";\n\nconst buttonGroupVariants = cva(\n  "flex w-fit items-stretch has-[>[data-slot=button-group]]:gap-2 [&>*]:focus-visible:relative [&>*]:focus-visible:z-10 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md [&>[data-slot=select-trigger]:not([class*=\'w-\'])]:w-fit [&>input]:flex-1",\n  {\n    variants: {\n      orientation: {\n        horizontal:\n          "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",\n        vertical:\n          "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none",\n      },\n    },\n    defaultVariants: {\n      orientation: "horizontal",\n    },\n  },\n);\n\nfunction ButtonGroup({\n  className,\n  orientation,\n  ...props\n}: React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>) {\n  return (\n    <div\n      role="group"\n      data-slot="button-group"\n      data-orientation={orientation}\n      className={cn(buttonGroupVariants({ orientation }), className)}\n      {...props}\n    />\n  );\n}\n\nfunction ButtonGroupText({\n  className,\n  asChild = false,\n  ...props\n}: React.ComponentProps<"div"> & {\n  asChild?: boolean;\n}) {\n  const Comp = asChild ? Slot.Root : "div";\n\n  return (\n    <Comp\n      className={cn(\n        "flex items-center gap-2 rounded-md border bg-muted px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*=\'size-\'])]:size-4",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction ButtonGroupSeparator({\n  className,\n  orientation = "vertical",\n  ...props\n}: React.ComponentProps<typeof Separator>) {\n  return (\n    <Separator\n      data-slot="button-group-separator"\n      orientation={orientation}\n      className={cn(\n        "relative m-0! self-stretch bg-input data-[orientation=vertical]:h-auto",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, buttonGroupVariants };\n';
    readonly "components/ui/button.tsx": 'import * as React from "react";\nimport { cva, type VariantProps } from "class-variance-authority";\nimport { Slot } from "radix-ui";\n\nimport { cn } from "@/lib/utils";\n\nconst buttonVariants = cva(\n  "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4",\n  {\n    variants: {\n      variant: {\n        default: "bg-primary text-primary-foreground hover:bg-primary/90",\n        destructive:\n          "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",\n        outline:\n          "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",\n        secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",\n        ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",\n        link: "text-primary underline-offset-4 hover:underline",\n      },\n      size: {\n        default: "h-9 px-4 py-2 has-[>svg]:px-3",\n        xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*=\'size-\'])]:size-3",\n        sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",\n        lg: "h-10 rounded-md px-6 has-[>svg]:px-4",\n        icon: "size-9",\n        "icon-xs": "size-6 rounded-md [&_svg:not([class*=\'size-\'])]:size-3",\n        "icon-sm": "size-8",\n        "icon-lg": "size-10",\n      },\n    },\n    defaultVariants: {\n      variant: "default",\n      size: "default",\n    },\n  },\n);\n\nfunction Button({\n  className,\n  variant = "default",\n  size = "default",\n  asChild = false,\n  ...props\n}: React.ComponentProps<"button"> &\n  VariantProps<typeof buttonVariants> & {\n    asChild?: boolean;\n  }) {\n  const Comp = asChild ? Slot.Root : "button";\n\n  return (\n    <Comp\n      data-slot="button"\n      data-variant={variant}\n      data-size={size}\n      className={cn(buttonVariants({ variant, size, className }))}\n      {...props}\n    />\n  );\n}\n\nexport { Button, buttonVariants };\n';
    readonly "components/ui/collapsible.tsx": '"use client";\n\nimport { Collapsible as CollapsiblePrimitive } from "radix-ui";\n\nfunction Collapsible({ ...props }: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {\n  return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />;\n}\n\nfunction CollapsibleTrigger({\n  ...props\n}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {\n  return <CollapsiblePrimitive.CollapsibleTrigger data-slot="collapsible-trigger" {...props} />;\n}\n\nfunction CollapsibleContent({\n  ...props\n}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {\n  return <CollapsiblePrimitive.CollapsibleContent data-slot="collapsible-content" {...props} />;\n}\n\nexport { Collapsible, CollapsibleTrigger, CollapsibleContent };\n';
    readonly "components/ui/command.tsx": '"use client";\n\nimport * as React from "react";\nimport { Command as CommandPrimitive } from "cmdk";\nimport { SearchIcon } from "lucide-react";\n\nimport { cn } from "@/lib/utils";\nimport {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogHeader,\n  DialogTitle,\n} from "@/components/ui/dialog";\n\nfunction Command({ className, ...props }: React.ComponentProps<typeof CommandPrimitive>) {\n  return (\n    <CommandPrimitive\n      data-slot="command"\n      className={cn(\n        "flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction CommandDialog({\n  title = "Command Palette",\n  description = "Search for a command to run...",\n  children,\n  className,\n  showCloseButton = true,\n  ...props\n}: React.ComponentProps<typeof Dialog> & {\n  title?: string;\n  description?: string;\n  className?: string;\n  showCloseButton?: boolean;\n}) {\n  return (\n    <Dialog {...props}>\n      <DialogHeader className="sr-only">\n        <DialogTitle>{title}</DialogTitle>\n        <DialogDescription>{description}</DialogDescription>\n      </DialogHeader>\n      <DialogContent\n        className={cn("overflow-hidden p-0", className)}\n        showCloseButton={showCloseButton}\n      >\n        <Command className="**:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">\n          {children}\n        </Command>\n      </DialogContent>\n    </Dialog>\n  );\n}\n\nfunction CommandInput({\n  className,\n  ...props\n}: React.ComponentProps<typeof CommandPrimitive.Input>) {\n  return (\n    <div data-slot="command-input-wrapper" className="flex h-9 items-center gap-2 border-b px-3">\n      <SearchIcon className="size-4 shrink-0 opacity-50" />\n      <CommandPrimitive.Input\n        data-slot="command-input"\n        className={cn(\n          "flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",\n          className,\n        )}\n        {...props}\n      />\n    </div>\n  );\n}\n\nfunction CommandList({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.List>) {\n  return (\n    <CommandPrimitive.List\n      data-slot="command-list"\n      className={cn("max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto", className)}\n      {...props}\n    />\n  );\n}\n\nfunction CommandEmpty({ ...props }: React.ComponentProps<typeof CommandPrimitive.Empty>) {\n  return (\n    <CommandPrimitive.Empty\n      data-slot="command-empty"\n      className="py-6 text-center text-sm"\n      {...props}\n    />\n  );\n}\n\nfunction CommandGroup({\n  className,\n  ...props\n}: React.ComponentProps<typeof CommandPrimitive.Group>) {\n  return (\n    <CommandPrimitive.Group\n      data-slot="command-group"\n      className={cn(\n        "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction CommandSeparator({\n  className,\n  ...props\n}: React.ComponentProps<typeof CommandPrimitive.Separator>) {\n  return (\n    <CommandPrimitive.Separator\n      data-slot="command-separator"\n      className={cn("-mx-1 h-px bg-border", className)}\n      {...props}\n    />\n  );\n}\n\nfunction CommandItem({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Item>) {\n  return (\n    <CommandPrimitive.Item\n      data-slot="command-item"\n      className={cn(\n        "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4 [&_svg:not([class*=\'text-\'])]:text-muted-foreground",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction CommandShortcut({ className, ...props }: React.ComponentProps<"span">) {\n  return (\n    <span\n      data-slot="command-shortcut"\n      className={cn("ml-auto text-xs tracking-widest text-muted-foreground", className)}\n      {...props}\n    />\n  );\n}\n\nexport {\n  Command,\n  CommandDialog,\n  CommandInput,\n  CommandList,\n  CommandEmpty,\n  CommandGroup,\n  CommandItem,\n  CommandShortcut,\n  CommandSeparator,\n};\n';
    readonly "components/ui/dialog.tsx": '"use client";\n\nimport * as React from "react";\nimport { XIcon } from "lucide-react";\nimport { Dialog as DialogPrimitive } from "radix-ui";\n\nimport { cn } from "@/lib/utils";\nimport { Button } from "@/components/ui/button";\n\nfunction Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>) {\n  return <DialogPrimitive.Root data-slot="dialog" {...props} />;\n}\n\nfunction DialogTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n  return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;\n}\n\nfunction DialogPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n  return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;\n}\n\nfunction DialogClose({ ...props }: React.ComponentProps<typeof DialogPrimitive.Close>) {\n  return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;\n}\n\nfunction DialogOverlay({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n  return (\n    <DialogPrimitive.Overlay\n      data-slot="dialog-overlay"\n      className={cn(\n        "fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction DialogContent({\n  className,\n  children,\n  showCloseButton = true,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Content> & {\n  showCloseButton?: boolean;\n}) {\n  return (\n    <DialogPortal data-slot="dialog-portal">\n      <DialogOverlay />\n      <DialogPrimitive.Content\n        data-slot="dialog-content"\n        className={cn(\n          "fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg duration-200 outline-none data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:max-w-lg",\n          className,\n        )}\n        {...props}\n      >\n        {children}\n        {showCloseButton && (\n          <DialogPrimitive.Close\n            data-slot="dialog-close"\n            className="absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4"\n          >\n            <XIcon />\n            <span className="sr-only">Close</span>\n          </DialogPrimitive.Close>\n        )}\n      </DialogPrimitive.Content>\n    </DialogPortal>\n  );\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<"div">) {\n  return (\n    <div\n      data-slot="dialog-header"\n      className={cn("flex flex-col gap-2 text-center sm:text-left", className)}\n      {...props}\n    />\n  );\n}\n\nfunction DialogFooter({\n  className,\n  showCloseButton = false,\n  children,\n  ...props\n}: React.ComponentProps<"div"> & {\n  showCloseButton?: boolean;\n}) {\n  return (\n    <div\n      data-slot="dialog-footer"\n      className={cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className)}\n      {...props}\n    >\n      {children}\n      {showCloseButton && (\n        <DialogPrimitive.Close asChild>\n          <Button variant="outline">Close</Button>\n        </DialogPrimitive.Close>\n      )}\n    </div>\n  );\n}\n\nfunction DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {\n  return (\n    <DialogPrimitive.Title\n      data-slot="dialog-title"\n      className={cn("text-lg leading-none font-semibold", className)}\n      {...props}\n    />\n  );\n}\n\nfunction DialogDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n  return (\n    <DialogPrimitive.Description\n      data-slot="dialog-description"\n      className={cn("text-sm text-muted-foreground", className)}\n      {...props}\n    />\n  );\n}\n\nexport {\n  Dialog,\n  DialogClose,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogOverlay,\n  DialogPortal,\n  DialogTitle,\n  DialogTrigger,\n};\n';
    readonly "components/ui/dropdown-menu.tsx": '"use client";\n\nimport * as React from "react";\nimport { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";\nimport { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";\n\nimport { cn } from "@/lib/utils";\n\nfunction DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {\n  return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;\n}\n\nfunction DropdownMenuPortal({\n  ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {\n  return <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />;\n}\n\nfunction DropdownMenuTrigger({\n  ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {\n  return <DropdownMenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />;\n}\n\nfunction DropdownMenuContent({\n  className,\n  sideOffset = 4,\n  ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {\n  return (\n    <DropdownMenuPrimitive.Portal>\n      <DropdownMenuPrimitive.Content\n        data-slot="dropdown-menu-content"\n        sideOffset={sideOffset}\n        className={cn(\n          "z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",\n          className,\n        )}\n        {...props}\n      />\n    </DropdownMenuPrimitive.Portal>\n  );\n}\n\nfunction DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {\n  return <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />;\n}\n\nfunction DropdownMenuItem({\n  className,\n  inset,\n  variant = "default",\n  ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {\n  inset?: boolean;\n  variant?: "default" | "destructive";\n}) {\n  return (\n    <DropdownMenuPrimitive.Item\n      data-slot="dropdown-menu-item"\n      data-inset={inset}\n      data-variant={variant}\n      className={cn(\n        "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4 [&_svg:not([class*=\'text-\'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction DropdownMenuCheckboxItem({\n  className,\n  children,\n  checked,\n  ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {\n  return (\n    <DropdownMenuPrimitive.CheckboxItem\n      data-slot="dropdown-menu-checkbox-item"\n      className={cn(\n        "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4",\n        className,\n      )}\n      checked={checked}\n      {...props}\n    >\n      <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">\n        <DropdownMenuPrimitive.ItemIndicator>\n          <CheckIcon className="size-4" />\n        </DropdownMenuPrimitive.ItemIndicator>\n      </span>\n      {children}\n    </DropdownMenuPrimitive.CheckboxItem>\n  );\n}\n\nfunction DropdownMenuRadioGroup({\n  ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {\n  return <DropdownMenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />;\n}\n\nfunction DropdownMenuRadioItem({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {\n  return (\n    <DropdownMenuPrimitive.RadioItem\n      data-slot="dropdown-menu-radio-item"\n      className={cn(\n        "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4",\n        className,\n      )}\n      {...props}\n    >\n      <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">\n        <DropdownMenuPrimitive.ItemIndicator>\n          <CircleIcon className="size-2 fill-current" />\n        </DropdownMenuPrimitive.ItemIndicator>\n      </span>\n      {children}\n    </DropdownMenuPrimitive.RadioItem>\n  );\n}\n\nfunction DropdownMenuLabel({\n  className,\n  inset,\n  ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {\n  inset?: boolean;\n}) {\n  return (\n    <DropdownMenuPrimitive.Label\n      data-slot="dropdown-menu-label"\n      data-inset={inset}\n      className={cn("px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", className)}\n      {...props}\n    />\n  );\n}\n\nfunction DropdownMenuSeparator({\n  className,\n  ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {\n  return (\n    <DropdownMenuPrimitive.Separator\n      data-slot="dropdown-menu-separator"\n      className={cn("-mx-1 my-1 h-px bg-border", className)}\n      {...props}\n    />\n  );\n}\n\nfunction DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">) {\n  return (\n    <span\n      data-slot="dropdown-menu-shortcut"\n      className={cn("ml-auto text-xs tracking-widest text-muted-foreground", className)}\n      {...props}\n    />\n  );\n}\n\nfunction DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {\n  return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;\n}\n\nfunction DropdownMenuSubTrigger({\n  className,\n  inset,\n  children,\n  ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {\n  inset?: boolean;\n}) {\n  return (\n    <DropdownMenuPrimitive.SubTrigger\n      data-slot="dropdown-menu-sub-trigger"\n      data-inset={inset}\n      className={cn(\n        "flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4 [&_svg:not([class*=\'text-\'])]:text-muted-foreground",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n      <ChevronRightIcon className="ml-auto size-4" />\n    </DropdownMenuPrimitive.SubTrigger>\n  );\n}\n\nfunction DropdownMenuSubContent({\n  className,\n  ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {\n  return (\n    <DropdownMenuPrimitive.SubContent\n      data-slot="dropdown-menu-sub-content"\n      className={cn(\n        "z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport {\n  DropdownMenu,\n  DropdownMenuPortal,\n  DropdownMenuTrigger,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuLabel,\n  DropdownMenuItem,\n  DropdownMenuCheckboxItem,\n  DropdownMenuRadioGroup,\n  DropdownMenuRadioItem,\n  DropdownMenuSeparator,\n  DropdownMenuShortcut,\n  DropdownMenuSub,\n  DropdownMenuSubTrigger,\n  DropdownMenuSubContent,\n};\n';
    readonly "components/ui/hover-card.tsx": '"use client";\n\nimport * as React from "react";\nimport { HoverCard as HoverCardPrimitive } from "radix-ui";\n\nimport { cn } from "@/lib/utils";\n\nfunction HoverCard({ ...props }: React.ComponentProps<typeof HoverCardPrimitive.Root>) {\n  return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />;\n}\n\nfunction HoverCardTrigger({ ...props }: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {\n  return <HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />;\n}\n\nfunction HoverCardContent({\n  className,\n  align = "center",\n  sideOffset = 4,\n  ...props\n}: React.ComponentProps<typeof HoverCardPrimitive.Content>) {\n  return (\n    <HoverCardPrimitive.Portal data-slot="hover-card-portal">\n      <HoverCardPrimitive.Content\n        data-slot="hover-card-content"\n        align={align}\n        sideOffset={sideOffset}\n        className={cn(\n          "z-50 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",\n          className,\n        )}\n        {...props}\n      />\n    </HoverCardPrimitive.Portal>\n  );\n}\n\nexport { HoverCard, HoverCardTrigger, HoverCardContent };\n';
    readonly "components/ui/input-group.tsx": '"use client";\n\nimport * as React from "react";\nimport { cva, type VariantProps } from "class-variance-authority";\n\nimport { cn } from "@/lib/utils";\nimport { Button } from "@/components/ui/button";\nimport { Input } from "@/components/ui/input";\nimport { Textarea } from "@/components/ui/textarea";\n\nfunction InputGroup({ className, ...props }: React.ComponentProps<"div">) {\n  return (\n    <div\n      data-slot="input-group"\n      role="group"\n      className={cn(\n        "group/input-group relative flex w-full items-center rounded-md border border-input shadow-xs transition-[color,box-shadow] outline-none dark:bg-input/30",\n        "h-9 min-w-0 has-[>textarea]:h-auto",\n\n        // Variants based on alignment.\n        "has-[>[data-align=inline-start]]:[&>input]:pl-2",\n        "has-[>[data-align=inline-end]]:[&>input]:pr-2",\n        "has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3",\n        "has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3",\n\n        // Focus state.\n        "has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-[3px] has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50",\n\n        // Error state.\n        "has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-destructive/20 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40",\n\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nconst inputGroupAddonVariants = cva(\n  "flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*=\'size-\'])]:size-4",\n  {\n    variants: {\n      align: {\n        "inline-start": "order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]",\n        "inline-end": "order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]",\n        "block-start":\n          "order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5 [.border-b]:pb-3",\n        "block-end":\n          "order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5 [.border-t]:pt-3",\n      },\n    },\n    defaultVariants: {\n      align: "inline-start",\n    },\n  },\n);\n\nfunction InputGroupAddon({\n  className,\n  align = "inline-start",\n  ...props\n}: React.ComponentProps<"div"> & VariantProps<typeof inputGroupAddonVariants>) {\n  return (\n    <div\n      role="group"\n      data-slot="input-group-addon"\n      data-align={align}\n      className={cn(inputGroupAddonVariants({ align }), className)}\n      onClick={(e) => {\n        if ((e.target as HTMLElement).closest("button")) {\n          return;\n        }\n        e.currentTarget.parentElement?.querySelector("input")?.focus();\n      }}\n      {...props}\n    />\n  );\n}\n\nconst inputGroupButtonVariants = cva("flex items-center gap-2 text-sm shadow-none", {\n  variants: {\n    size: {\n      xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*=\'size-\'])]:size-3.5",\n      sm: "h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5",\n      "icon-xs": "size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0",\n      "icon-sm": "size-8 p-0 has-[>svg]:p-0",\n    },\n  },\n  defaultVariants: {\n    size: "xs",\n  },\n});\n\nfunction InputGroupButton({\n  className,\n  type = "button",\n  variant = "ghost",\n  size = "xs",\n  ...props\n}: Omit<React.ComponentProps<typeof Button>, "size"> &\n  VariantProps<typeof inputGroupButtonVariants>) {\n  return (\n    <Button\n      type={type}\n      data-size={size}\n      variant={variant}\n      className={cn(inputGroupButtonVariants({ size }), className)}\n      {...props}\n    />\n  );\n}\n\nfunction InputGroupText({ className, ...props }: React.ComponentProps<"span">) {\n  return (\n    <span\n      className={cn(\n        "flex items-center gap-2 text-sm text-muted-foreground [&_svg]:pointer-events-none [&_svg:not([class*=\'size-\'])]:size-4",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction InputGroupInput({ className, ...props }: React.ComponentProps<"input">) {\n  return (\n    <Input\n      data-slot="input-group-control"\n      className={cn(\n        "flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction InputGroupTextarea({ className, ...props }: React.ComponentProps<"textarea">) {\n  return (\n    <Textarea\n      data-slot="input-group-control"\n      className={cn(\n        "flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport {\n  InputGroup,\n  InputGroupAddon,\n  InputGroupButton,\n  InputGroupText,\n  InputGroupInput,\n  InputGroupTextarea,\n};\n';
    readonly "components/ui/input.tsx": 'import * as React from "react";\n\nimport { cn } from "@/lib/utils";\n\nfunction Input({ className, type, ...props }: React.ComponentProps<"input">) {\n  return (\n    <input\n      type={type}\n      data-slot="input"\n      className={cn(\n        "h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30",\n        "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",\n        "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport { Input };\n';
    readonly "components/ui/select.tsx": '"use client";\n\nimport * as React from "react";\nimport { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";\nimport { Select as SelectPrimitive } from "radix-ui";\n\nimport { cn } from "@/lib/utils";\n\nfunction Select({ ...props }: React.ComponentProps<typeof SelectPrimitive.Root>) {\n  return <SelectPrimitive.Root data-slot="select" {...props} />;\n}\n\nfunction SelectGroup({ ...props }: React.ComponentProps<typeof SelectPrimitive.Group>) {\n  return <SelectPrimitive.Group data-slot="select-group" {...props} />;\n}\n\nfunction SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.Value>) {\n  return <SelectPrimitive.Value data-slot="select-value" {...props} />;\n}\n\nfunction SelectTrigger({\n  className,\n  size = "default",\n  children,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {\n  size?: "sm" | "default";\n}) {\n  return (\n    <SelectPrimitive.Trigger\n      data-slot="select-trigger"\n      data-size={size}\n      className={cn(\n        "flex w-fit items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[placeholder]:text-muted-foreground data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4 [&_svg:not([class*=\'text-\'])]:text-muted-foreground",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n      <SelectPrimitive.Icon asChild>\n        <ChevronDownIcon className="size-4 opacity-50" />\n      </SelectPrimitive.Icon>\n    </SelectPrimitive.Trigger>\n  );\n}\n\nfunction SelectContent({\n  className,\n  children,\n  position = "item-aligned",\n  align = "center",\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Content>) {\n  return (\n    <SelectPrimitive.Portal>\n      <SelectPrimitive.Content\n        data-slot="select-content"\n        className={cn(\n          "relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",\n          position === "popper" &&\n            "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",\n          className,\n        )}\n        position={position}\n        align={align}\n        {...props}\n      >\n        <SelectScrollUpButton />\n        <SelectPrimitive.Viewport\n          className={cn(\n            "p-1",\n            position === "popper" &&\n              "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1",\n          )}\n        >\n          {children}\n        </SelectPrimitive.Viewport>\n        <SelectScrollDownButton />\n      </SelectPrimitive.Content>\n    </SelectPrimitive.Portal>\n  );\n}\n\nfunction SelectLabel({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Label>) {\n  return (\n    <SelectPrimitive.Label\n      data-slot="select-label"\n      className={cn("px-2 py-1.5 text-xs text-muted-foreground", className)}\n      {...props}\n    />\n  );\n}\n\nfunction SelectItem({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Item>) {\n  return (\n    <SelectPrimitive.Item\n      data-slot="select-item"\n      className={cn(\n        "relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4 [&_svg:not([class*=\'text-\'])]:text-muted-foreground *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",\n        className,\n      )}\n      {...props}\n    >\n      <span\n        data-slot="select-item-indicator"\n        className="absolute right-2 flex size-3.5 items-center justify-center"\n      >\n        <SelectPrimitive.ItemIndicator>\n          <CheckIcon className="size-4" />\n        </SelectPrimitive.ItemIndicator>\n      </span>\n      <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n    </SelectPrimitive.Item>\n  );\n}\n\nfunction SelectSeparator({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Separator>) {\n  return (\n    <SelectPrimitive.Separator\n      data-slot="select-separator"\n      className={cn("pointer-events-none -mx-1 my-1 h-px bg-border", className)}\n      {...props}\n    />\n  );\n}\n\nfunction SelectScrollUpButton({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {\n  return (\n    <SelectPrimitive.ScrollUpButton\n      data-slot="select-scroll-up-button"\n      className={cn("flex cursor-default items-center justify-center py-1", className)}\n      {...props}\n    >\n      <ChevronUpIcon className="size-4" />\n    </SelectPrimitive.ScrollUpButton>\n  );\n}\n\nfunction SelectScrollDownButton({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {\n  return (\n    <SelectPrimitive.ScrollDownButton\n      data-slot="select-scroll-down-button"\n      className={cn("flex cursor-default items-center justify-center py-1", className)}\n      {...props}\n    >\n      <ChevronDownIcon className="size-4" />\n    </SelectPrimitive.ScrollDownButton>\n  );\n}\n\nexport {\n  Select,\n  SelectContent,\n  SelectGroup,\n  SelectItem,\n  SelectLabel,\n  SelectScrollDownButton,\n  SelectScrollUpButton,\n  SelectSeparator,\n  SelectTrigger,\n  SelectValue,\n};\n';
    readonly "components/ui/separator.tsx": '"use client";\n\nimport * as React from "react";\nimport { Separator as SeparatorPrimitive } from "radix-ui";\n\nimport { cn } from "@/lib/utils";\n\nfunction Separator({\n  className,\n  orientation = "horizontal",\n  decorative = true,\n  ...props\n}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {\n  return (\n    <SeparatorPrimitive.Root\n      data-slot="separator"\n      decorative={decorative}\n      orientation={orientation}\n      className={cn(\n        "shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport { Separator };\n';
    readonly "components/ui/spinner.tsx": 'import { Loader2Icon } from "lucide-react";\n\nimport { cn } from "@/lib/utils";\n\nfunction Spinner({ className, ...props }: React.ComponentProps<"svg">) {\n  return (\n    <Loader2Icon\n      role="status"\n      aria-label="Loading"\n      className={cn("size-4 animate-spin", className)}\n      {...props}\n    />\n  );\n}\n\nexport { Spinner };\n';
    readonly "components/ui/textarea.tsx": 'import * as React from "react";\n\nimport { cn } from "@/lib/utils";\n\nfunction Textarea({ className, ...props }: React.ComponentProps<"textarea">) {\n  return (\n    <textarea\n      data-slot="textarea"\n      className={cn(\n        "flex field-sizing-content min-h-16 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:aria-invalid:ring-destructive/40",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport { Textarea };\n';
    readonly "components/ui/tooltip.tsx": '"use client";\n\nimport * as React from "react";\nimport { Tooltip as TooltipPrimitive } from "radix-ui";\n\nimport { cn } from "@/lib/utils";\n\nfunction TooltipProvider({\n  delayDuration = 0,\n  ...props\n}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {\n  return (\n    <TooltipPrimitive.Provider\n      data-slot="tooltip-provider"\n      delayDuration={delayDuration}\n      {...props}\n    />\n  );\n}\n\nfunction Tooltip({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Root>) {\n  return <TooltipPrimitive.Root data-slot="tooltip" {...props} />;\n}\n\nfunction TooltipTrigger({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {\n  return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;\n}\n\nfunction TooltipContent({\n  className,\n  sideOffset = 0,\n  children,\n  ...props\n}: React.ComponentProps<typeof TooltipPrimitive.Content>) {\n  return (\n    <TooltipPrimitive.Portal>\n      <TooltipPrimitive.Content\n        data-slot="tooltip-content"\n        sideOffset={sideOffset}\n        className={cn(\n          "z-50 w-fit origin-(--radix-tooltip-content-transform-origin) animate-in rounded-md bg-foreground px-3 py-1.5 text-xs text-balance text-background fade-in-0 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",\n          className,\n        )}\n        {...props}\n      >\n        {children}\n        <TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" />\n      </TooltipPrimitive.Content>\n    </TooltipPrimitive.Portal>\n  );\n}\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };\n';
    readonly "components.json": '{\n  "$schema": "https://ui.shadcn.com/schema.json",\n  "style": "new-york",\n  "rsc": true,\n  "tsx": true,\n  "tailwind": {\n    "config": "",\n    "css": "app/globals.css",\n    "baseColor": "neutral",\n    "cssVariables": true,\n    "prefix": ""\n  },\n  "iconLibrary": "lucide",\n  "aliases": {\n    "components": "@/components",\n    "utils": "@/lib/utils",\n    "ui": "@/components/ui",\n    "lib": "@/lib",\n    "hooks": "@/hooks"\n  },\n  "registries": {}\n}\n';
    readonly "css.d.ts": 'declare module "*.css";\n';
    readonly "lib/utils.ts": 'import { clsx, type ClassValue } from "clsx";\nimport { twMerge } from "tailwind-merge";\n\nexport function cn(...inputs: ClassValue[]): string {\n  return twMerge(clsx(inputs));\n}\n';
    readonly "next-env.d.ts": '/// <reference types="next" />\n/// <reference types="next/image-types/global" />\nimport "./.next/types/routes.d.ts";\nimport "./.next/types/root-params.d.ts";\n\n// NOTE: This file should not be edited\n// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.\n';
    readonly "next.config.ts": 'import type { NextConfig } from "next";\nimport { withEve } from "eve/next";\n\nconst nextConfig: NextConfig = {};\n\nexport default withEve(nextConfig__EVE_INIT_WITH_EVE_OPTIONS__);\n';
    readonly "postcss.config.mjs": 'const config = {\n  plugins: {\n    "@tailwindcss/postcss": {},\n  },\n};\n\nexport default config;\n';
    readonly "tsconfig.json": '{\n  "$schema": "https://json.schemastore.org/tsconfig",\n  "compilerOptions": {\n    "target": "ES2017",\n    "lib": ["dom", "dom.iterable", "esnext"],\n    "allowJs": true,\n    "skipLibCheck": true,\n    "strict": true,\n    "noEmit": true,\n    "esModuleInterop": true,\n    "module": "esnext",\n    "moduleResolution": "Bundler",\n    "resolveJsonModule": true,\n    "isolatedModules": true,\n    "jsx": "react-jsx",\n    "incremental": true,\n    "plugins": [\n      {\n        "name": "next"\n      }\n    ],\n    "paths": {\n      "@/*": ["./*"]\n    }\n  },\n  "include": [\n    "next-env.d.ts",\n    "**/*.ts",\n    "**/*.tsx",\n    ".next/types/**/*.ts",\n    ".next/dev/types/**/*.ts"\n  ],\n  "exclude": ["node_modules"]\n}\n';
};
export declare const WEB_APP_SIGN_IN_WITH_VERCEL_TEMPLATE_FILES: {
    readonly "agent/channels/eve.ts": 'import { eveChannel } from "eve/channels/eve";\nimport { localDev, type AuthFn, vercelOidc } from "eve/channels/auth";\nimport { auth } from "@/lib/auth";\n\nconst betterAuthSession: AuthFn<Request> = async (request) => {\n  const session = await auth.api.getSession({ headers: request.headers });\n  if (!session) return null;\n\n  const attributes: Record<string, string> = {\n    email: session.user.email,\n    name: session.user.name,\n  };\n  if (session.user.image) {\n    attributes.picture = session.user.image;\n  }\n\n  return {\n    attributes,\n    authenticator: "better-auth:vercel",\n    principalId: session.user.id,\n    principalType: "user",\n  };\n};\n\nexport default eveChannel({\n  auth: [betterAuthSession, vercelOidc(), localDev()],\n});\n';
    readonly "app/_components/authenticated-agent-chat.tsx": 'import { headers } from "next/headers";\nimport { auth } from "@/lib/auth";\nimport { AgentChat } from "./agent-chat";\nimport { AccountControl, SignIn } from "./web-chat-auth";\n\nexport async function AuthenticatedAgentChat({\n  sessionId,\n  sessionless,\n}: {\n  readonly sessionId?: string;\n  readonly sessionless?: boolean;\n}) {\n  if (process.env.NODE_ENV === "development") {\n    return <AgentChat sessionId={sessionId} sessionless={sessionless} />;\n  }\n\n  const session = await auth.api.getSession({ headers: await headers() });\n  if (!session) return <SignIn />;\n\n  return (\n    <>\n      <AgentChat sessionId={sessionId} sessionless={sessionless} />\n      <AccountControl\n        email={session.user.email}\n        image={session.user.image}\n        name={session.user.name}\n      />\n    </>\n  );\n}\n';
    readonly "app/_components/web-chat-auth.tsx": '"use client";\n\nimport { LogOutIcon } from "lucide-react";\nimport { useState } from "react";\nimport { Button } from "@/components/ui/button";\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from "@/components/ui/dropdown-menu";\nimport { authClient } from "@/lib/auth-client";\n\nconst AGENT_NAME = "__EVE_INIT_APP_NAME__";\n\nexport function SignIn() {\n  const [pending, setPending] = useState(false);\n  const [error, setError] = useState<string>();\n\n  async function signIn() {\n    setPending(true);\n    setError(undefined);\n    try {\n      const result = await authClient.signIn.social({\n        callbackURL: "/",\n        provider: "vercel",\n      });\n      if (!result.error) return;\n      setPending(false);\n      setError("Sign-in failed. Try again.");\n    } catch {\n      setPending(false);\n      setError("Sign-in failed. Try again.");\n    }\n  }\n\n  return (\n    <main className="flex min-h-dvh items-center justify-center bg-background px-8 text-foreground">\n      <div className="flex w-full max-w-[22rem] flex-col gap-5">\n        <div className="text-foreground opacity-[0.08] dark:opacity-[0.12]">\n          <EveWordmark className="h-auto w-[4.875rem]" />\n        </div>\n        <section aria-label="Sign in" className="flex flex-col gap-2">\n          <h1 className="max-w-full break-words font-medium text-sm leading-6">{AGENT_NAME}</h1>\n          <p className="flex flex-wrap items-center gap-2 text-muted-foreground text-sm leading-6">\n            <span className="inline-flex items-center gap-2 text-emerald-600 dark:text-emerald-400">\n              <span aria-hidden="true" className="size-1.5 rounded-full bg-current" />\n              Ready\n            </span>\n            <span aria-hidden="true" className="text-border">\n              /\n            </span>\n            <span>Sign in to start a session</span>\n          </p>\n          <Button className="mt-3 w-full gap-2 text-sm" disabled={pending} onClick={signIn}>\n            <svg aria-hidden="true" className="size-3 fill-current" viewBox="0 0 24 20">\n              <path d="M12 0 24 20H0L12 0Z" />\n            </svg>\n            <span className="leading-5">{pending ? "Redirecting…" : "Continue with Vercel"}</span>\n          </Button>\n          {error ? (\n            <p className="text-destructive text-sm" role="alert">\n              {error}\n            </p>\n          ) : null}\n        </section>\n      </div>\n    </main>\n  );\n}\n\nfunction EveWordmark({ className }: { readonly className?: string }) {\n  return (\n    <svg\n      aria-hidden="true"\n      className={className}\n      fill="none"\n      viewBox="0 0 169 53"\n      xmlns="http://www.w3.org/2000/svg"\n    >\n      <path\n        d="M169 8.47h-51.39L81.73 53H70.36L113 0H169zM169 44.51v8.47h-45.87V44.5zM45.87 52.98H0V44.5h45.87zM38.66 30.55H0v-8.47h38.66z"\n        fill="currentColor"\n      />\n      <path d="M169 30.55h-38.66v-8.47H169zM75.52 8.47H0V0h75.52z" fill="currentColor" />\n    </svg>\n  );\n}\n\nexport function AccountControl({\n  email,\n  image,\n  name,\n}: {\n  readonly email: string;\n  readonly image?: string | null;\n  readonly name: string;\n}) {\n  const [imageFailed, setImageFailed] = useState(false);\n  const [pending, setPending] = useState(false);\n  const initials = getInitials(name, email);\n\n  async function signOut() {\n    setPending(true);\n    try {\n      await authClient.signOut({\n        fetchOptions: {\n          onError: () => setPending(false),\n          onSuccess: () => window.location.assign("/"),\n        },\n      });\n    } catch {\n      setPending(false);\n    }\n  }\n\n  return (\n    <div className="fixed top-3 left-4 z-30 flex h-8 items-center">\n      <DropdownMenu>\n        <DropdownMenuTrigger asChild>\n          <Button\n            aria-label={`Open account menu for ${name}`}\n            className="relative size-7 cursor-pointer overflow-hidden rounded-full p-0"\n            size="icon-sm"\n            variant="ghost"\n          >\n            {image && !imageFailed ? (\n              <img\n                alt=""\n                className="size-full object-cover"\n                onError={() => setImageFailed(true)}\n                src={image}\n              />\n            ) : (\n              <span aria-hidden="true" className="font-medium text-xs">\n                {initials}\n              </span>\n            )}\n            <span\n              aria-hidden="true"\n              className="pointer-events-none absolute inset-0 rounded-full border border-black/20 dark:border-white/25"\n            />\n          </Button>\n        </DropdownMenuTrigger>\n        <DropdownMenuContent align="start" className="w-64">\n          <div className="min-w-0 px-2 py-1.5 text-sm">\n            <span className="block truncate font-medium leading-5" title={name}>\n              {name}\n            </span>\n            <span className="block truncate text-muted-foreground leading-5" title={email}>\n              {email}\n            </span>\n          </div>\n          <DropdownMenuSeparator />\n          <DropdownMenuItem\n            className="cursor-pointer justify-between"\n            disabled={pending}\n            onSelect={signOut}\n          >\n            {pending ? "Logging out…" : "Log out"}\n            <LogOutIcon aria-hidden="true" />\n          </DropdownMenuItem>\n        </DropdownMenuContent>\n      </DropdownMenu>\n    </div>\n  );\n}\n\nfunction getInitials(name: string, email: string): string {\n  const parts = name.trim().split(/\\s+/).filter(Boolean);\n  if (parts.length >= 2) {\n    return `${parts[0]?.[0] ?? ""}${parts.at(-1)?.[0] ?? ""}`.toUpperCase();\n  }\n  return (parts[0]?.[0] ?? email[0] ?? "?").toUpperCase();\n}\n';
    readonly "app/api/auth/[...all]/route.ts": 'import { toNextJsHandler } from "better-auth/next-js";\nimport { auth } from "@/lib/auth";\n\nexport const { GET, POST } = toNextJsHandler(auth);\n';
    readonly "app/layout.tsx": 'import type { Metadata } from "next";\nimport { Geist, Geist_Mono } from "next/font/google";\nimport type { ReactNode } from "react";\nimport { TooltipProvider } from "@/components/ui/tooltip";\nimport { cn } from "@/lib/utils";\nimport "./globals.css";\n\nconst sans = Geist({\n  variable: "--font-sans",\n  subsets: ["latin"],\n  weight: "variable",\n  display: "swap",\n});\n\nconst mono = Geist_Mono({\n  variable: "--font-mono",\n  subsets: ["latin"],\n  weight: "variable",\n  display: "swap",\n});\n\nexport const metadata: Metadata = {\n  title: "__EVE_INIT_APP_NAME__",\n  description: "A Next.js starter for eve agents with AI Elements.",\n};\n\n// The page and Eve routes validate the generated app\'s Better Auth session.\nexport default function RootLayout({ children }: { readonly children: ReactNode }) {\n  return (\n    <html className={cn(sans.variable, mono.variable)} lang="en">\n      <body>\n        <TooltipProvider>{children}</TooltipProvider>\n      </body>\n    </html>\n  );\n}\n';
    readonly "app/page.tsx": 'import { AuthenticatedAgentChat } from "./_components/authenticated-agent-chat";\n\nexport default function Page() {\n  return <AuthenticatedAgentChat />;\n}\n';
    readonly "app/s/[sessionId]/page.tsx": 'import { AuthenticatedAgentChat } from "@/app/_components/authenticated-agent-chat";\n\nexport default async function SessionPage({\n  params,\n}: {\n  readonly params: Promise<{ readonly sessionId: string }>;\n}) {\n  const { sessionId } = await params;\n  return <AuthenticatedAgentChat sessionId={sessionId} />;\n}\n';
    readonly "app/s/page.tsx": 'import { AuthenticatedAgentChat } from "@/app/_components/authenticated-agent-chat";\n\nexport default function NewSessionPage() {\n  return <AuthenticatedAgentChat sessionless />;\n}\n';
    readonly "lib/auth-client.ts": '"use client";\n\nimport { createAuthClient } from "better-auth/react";\n\nexport const authClient = createAuthClient();\n';
    readonly "lib/auth.ts": 'import { betterAuth } from "better-auth";\n\nconst SESSION_MAX_AGE_SECONDS = 8 * 60 * 60;\nconst DEVELOPMENT_ALLOWED_HOSTS = ["localhost:*", "127.0.0.1:*"];\n\nfunction getAllowedHosts(): string[] {\n  if (process.env.NODE_ENV === "development") {\n    return DEVELOPMENT_ALLOWED_HOSTS;\n  }\n  const deploymentHosts = [\n    process.env.VERCEL_URL,\n    process.env.VERCEL_BRANCH_URL,\n    process.env.VERCEL_PROJECT_PRODUCTION_URL,\n  ].filter((host): host is string => Boolean(host));\n  if (deploymentHosts.length === 0) {\n    throw new Error("No trusted deployment hosts are configured");\n  }\n  return Array.from(new Set(deploymentHosts));\n}\n\nfunction requireEnvironmentVariable(name: string): string {\n  const value = process.env[name];\n  if (value) return value;\n  if (process.env.NODE_ENV === "development") return `development-${name}`;\n  throw new Error(`Missing required environment variable: ${name}`);\n}\n\nexport const auth = betterAuth({\n  baseURL: {\n    allowedHosts: getAllowedHosts(),\n    protocol: process.env.NODE_ENV === "development" ? "auto" : "https",\n  },\n  secret: requireEnvironmentVariable("BETTER_AUTH_SECRET"),\n  session: {\n    expiresIn: SESSION_MAX_AGE_SECONDS,\n    disableSessionRefresh: true,\n    cookieCache: {\n      enabled: true,\n      maxAge: SESSION_MAX_AGE_SECONDS,\n      refreshCache: false,\n      strategy: "jwe",\n    },\n  },\n  socialProviders: {\n    vercel: {\n      clientId: requireEnvironmentVariable("VERCEL_APP_CLIENT_ID"),\n      clientSecret: requireEnvironmentVariable("VERCEL_APP_CLIENT_SECRET"),\n    },\n  },\n});\n';
};
export declare const WEB_APP_TEMPLATE_PACKAGE_JSON: {
    readonly scripts: {
        readonly build: "next build";
        readonly "build:eve": "eve build";
        readonly dev: "next dev";
        readonly "dev:eve": "eve dev";
        readonly start: "next start";
        readonly "start:eve": "eve start";
        readonly typecheck: "tsc --noEmit -p tsconfig.json";
    };
    readonly dependencies: {
        readonly "@radix-ui/react-use-controllable-state": "1.2.2";
        readonly "@shikijs/core": "3.23.0";
        readonly "@shikijs/engine-javascript": "3.23.0";
        readonly "@shikijs/engine-oniguruma": "3.23.0";
        readonly "@streamdown/cjk": "1.0.3";
        readonly "@streamdown/code": "1.1.1";
        readonly "@streamdown/math": "1.0.2";
        readonly "@streamdown/mermaid": "1.0.2";
        readonly "@tailwindcss/postcss": "4.3.0";
        readonly "class-variance-authority": "0.7.1";
        readonly clsx: "2.1.1";
        readonly cmdk: "1.1.1";
        readonly "lucide-react": "1.16.0";
        readonly motion: "12.40.0";
        readonly nanoid: "5.1.11";
        readonly next: "16.3.0-preview.6";
        readonly "radix-ui": "1.4.3";
        readonly react: "19.2.6";
        readonly "react-dom": "19.2.6";
        readonly shiki: "3.23.0";
        readonly streamdown: "2.5.0";
        readonly "tailwind-merge": "3.6.0";
        readonly tailwindcss: "4.3.0";
        readonly "use-stick-to-bottom": "1.1.4";
        readonly zod: "4.5.4";
    };
    readonly devDependencies: {
        readonly "@types/node": "26";
        readonly "@types/react": "19.2.15";
        readonly "@types/react-dom": "19.2.3";
        readonly typescript: "6.0.3";
    };
};
