import React, { useEffect } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { ScrollArea } from "@/components/ui/scroll-area"; import { BookOpen, Box, Database, GitBranch, ListChecks, Server, Shield, Wrench, FileText, } from "lucide-react"; // Types describing the expected analysis payload export interface StackSection { framework?: string; language?: string; package_manager?: string; styling?: string; dependency_manager?: string; architecture?: string; key_libraries?: string[]; [key: string]: unknown; } export interface RootFileEntry { file: string; description: string; } export interface RiskNote { area: string; note: string; } export interface StackAnalysis { purpose?: string; frontend?: StackSection; backend?: StackSection; database?: { type?: string; notes?: string }; infrastructure?: { hosting_frontend?: string; hosting_backend?: string; dependencies?: string[]; }; ci_cd?: { setup?: string }; key_root_files?: RootFileEntry[]; how_to_run?: { summary?: string; steps?: string[] }; risks_notes?: RiskNote[]; [key: string]: unknown; } function isNonEmptyArray(arr: T[] | undefined | null): arr is T[] { return Array.isArray(arr) && arr.length > 0; } function humanize(key: string): string { return key.replaceAll("_", " ").replace(/\b\w/g, (m) => m.toUpperCase()); } function gridColsClass(count: number): string { if (count >= 3) return "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6 items-stretch"; if (count === 2) return "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-2 gap-6 items-stretch"; return "grid grid-cols-1 gap-6 items-stretch"; } function SectionCard({ title, icon: Icon, children, className = "", }: { title: string; icon: React.ComponentType<{ className?: string }>; children: React.ReactNode; className?: string; }) { return (
{title}
{children}
); } function DefinitionList({ data, order, }: { data?: Record; order?: string[]; }) { if (!data) return null; const entries = Object.entries(data).filter( ([k, v]) => v !== undefined && v !== null && k !== "key_libraries", ); const orderedEntries = order ? entries.sort((a, b) => order.indexOf(a[0]) - order.indexOf(b[0])) : entries; return (
{orderedEntries.map(([key, value]) => (
{humanize(key)}
{String(value)}
))} {isNonEmptyArray((data as any).key_libraries) && (
Key Libraries
{((data as any).key_libraries as string[]).map((lib) => ( {lib} ))}
)}
); } export function StackAnalysisCards({ analysis, }: { analysis?: StackAnalysis | string; }) { useEffect(() => { console.log(analysis, "analysis"); }, [analysis]); // Accept either object or JSON string let parsed: StackAnalysis | undefined; if (!analysis) parsed = undefined; else if (typeof analysis === "string") { try { parsed = JSON.parse(analysis) as StackAnalysis; } catch { parsed = undefined; } } else { parsed = analysis; } if (!parsed || Object.keys(parsed).length === 0) { return (
No analysis available yet. Ask the agent to analyze a repository.
); } const topCards = [ parsed.frontend, parsed.backend, parsed.database, parsed.infrastructure, parsed.ci_cd, ].filter(Boolean); const bottomCardsCount = [ isNonEmptyArray(parsed.key_root_files), Boolean(parsed.how_to_run), isNonEmptyArray(parsed.risks_notes), ].filter(Boolean).length; return (
{parsed.purpose && (

{parsed.purpose}

)}
{parsed.frontend && ( } order={["language", "framework", "package_manager", "styling"]} /> )} {parsed.backend && ( } order={[ "language", "framework", "dependency_manager", "architecture", ]} /> )} {parsed.database && ( } order={["type", "notes"]} /> )} {parsed.infrastructure && ( } order={["hosting_frontend", "hosting_backend"]} /> {isNonEmptyArray(parsed.infrastructure?.dependencies) && (
Dependencies
{(parsed.infrastructure?.dependencies as string[]).map( (dep) => ( {dep} ), )}
)}
)} {parsed.ci_cd && ( } order={["setup"]} /> )}
{(isNonEmptyArray(parsed.key_root_files) || parsed.how_to_run || isNonEmptyArray(parsed.risks_notes)) && (
{isNonEmptyArray(parsed.key_root_files) && (
{parsed.key_root_files!.map((f) => (
{f.file}
{f.description}
))}
)} {parsed.how_to_run && ( {parsed.how_to_run?.summary && (

{parsed.how_to_run.summary}

)} {isNonEmptyArray(parsed.how_to_run?.steps) && (
    {parsed.how_to_run!.steps!.map((step, idx) => (
  1. {step}
  2. ))}
)}
)} {isNonEmptyArray(parsed.risks_notes) && (
{parsed.risks_notes!.map((r, idx) => (
{r.area}
{r.note}
))}
)}
)}
); } export default StackAnalysisCards;