import * as React from "react"; import Markdown from "react-markdown"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism"; import type { WizardStateData } from "../api/client"; import type { Message } from "../types"; import { MessageItem } from "./MessageItem"; import SetupWizard from "./SetupWizard"; const { useEffect, useRef } = React; /** Fixed-height thinking trace block that auto-scrolls to bottom as text arrives. */ export function ThinkingBlock({ text }: { text: string }) { const scrollRef = useRef(null); useEffect(() => { const el = scrollRef.current; if (el) { el.scrollTop = el.scrollHeight; } }, [text]); return (
thinking {text}
); } /** Streaming message renderer — stable component to avoid recreation on each render. */ export function StreamingMessage({ content }: { content: string }) { return ( { const match = /language-(\w+)/.exec(className || ""); const isInline = !className; return !isInline && match ? ( {String(children).replace(/\n$/, "")} ) : ( {children} ); }, }} > {content} ); } interface ChatMessageListProps { messages: Message[]; loading: boolean; streamingContent: string; streamingThinking: string; activityStatus: string | null; wizardState: WizardStateData | null; setWizardState: React.Dispatch>; needsOnboarding: boolean; setNeedsOnboarding: React.Dispatch>; sendMessage: (text: string) => void; scrollContainerRef: React.RefObject; messagesEndRef: React.RefObject; onScroll: () => void; onboardingTriggeredRef: React.MutableRefObject; } export function ChatMessageList({ messages, loading, streamingContent, streamingThinking, activityStatus, wizardState, setWizardState, needsOnboarding, setNeedsOnboarding, sendMessage, scrollContainerRef, messagesEndRef, onScroll, onboardingTriggeredRef, }: ChatMessageListProps) { return (
{wizardState && !wizardState.completed && messages.length === 0 && !loading && ( )} {needsOnboarding && !wizardState && messages.length === 0 && !loading && (

Welcome to Huskies

This project needs to be set up before you can start writing stories. The agent will guide you through configuring your project goals and tech stack.

)} {messages.map((msg: Message, idx: number) => ( ))} {loading && streamingThinking && ( )} {loading && streamingContent && (
)} {loading && (activityStatus != null || (!streamingContent && !streamingThinking)) && (
{activityStatus ?? "Thinking..."}
)}
); }