-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlint_errors.json
More file actions
1 lines (1 loc) · 203 KB
/
lint_errors.json
File metadata and controls
1 lines (1 loc) · 203 KB
1
[{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\app\\api\\agents\\run\\route.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\app\\api\\analytics\\route.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\app\\api\\download\\ppt\\[projectId]\\route.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\app\\api\\projects\\[id]\\route.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":20,"column":18,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":20,"endColumn":21,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[642,645],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[642,645],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { NextRequest, NextResponse } from 'next/server';\r\nimport { prisma } from '@/lib/prisma';\r\n\r\nexport async function GET(\r\n request: NextRequest,\r\n props: { params: Promise<{ id: string }> }\r\n) {\r\n const params = await props.params;\r\n try {\r\n const project = await prisma.project.findUnique({\r\n where: { id: params.id },\r\n include: {\r\n documents: true,\r\n agentRuns: {\r\n orderBy: { createdAt: 'desc' },\r\n },\r\n hypotheses: true,\r\n conceptNodes: true,\r\n statistics: true,\r\n } as any,\r\n });\r\n\r\n if (!project) {\r\n return NextResponse.json(\r\n { error: 'Project not found' },\r\n { status: 404 }\r\n );\r\n }\r\n\r\n return NextResponse.json(project);\r\n } catch (error) {\r\n console.error('GET /api/projects/[id] error:', error);\r\n return NextResponse.json(\r\n { error: 'Failed to fetch project' },\r\n { status: 500 }\r\n );\r\n }\r\n}\r\n\r\nexport async function DELETE(\r\n request: NextRequest,\r\n props: { params: Promise<{ id: string }> }\r\n) {\r\n const params = await props.params;\r\n try {\r\n await prisma.project.delete({\r\n where: { id: params.id },\r\n });\r\n\r\n return NextResponse.json({ success: true });\r\n } catch (error) {\r\n console.error('DELETE /api/projects/[id] error:', error);\r\n return NextResponse.json(\r\n { error: 'Failed to delete project' },\r\n { status: 500 }\r\n );\r\n }\r\n}\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\app\\api\\projects\\route.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\app\\api\\upload\\route.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\app\\layout.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\app\\page.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'AgentPipeline' is defined but never used.","line":6,"column":10,"nodeType":null,"messageId":"unusedVar","endLine":6,"endColumn":23},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'HypothesisTable' is defined but never used.","line":11,"column":10,"nodeType":null,"messageId":"unusedVar","endLine":11,"endColumn":25},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'FileUpload' is defined but never used.","line":13,"column":10,"nodeType":null,"messageId":"unusedVar","endLine":13,"endColumn":20},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'mockAgents' is defined but never used.","line":23,"column":3,"nodeType":null,"messageId":"unusedVar","endLine":23,"endColumn":13},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'mockQualityMetrics' is defined but never used.","line":24,"column":3,"nodeType":null,"messageId":"unusedVar","endLine":24,"endColumn":21},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'mockCitationData' is defined but never used.","line":25,"column":3,"nodeType":null,"messageId":"unusedVar","endLine":25,"endColumn":19},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'mockWordCountTrend' is defined but never used.","line":26,"column":3,"nodeType":null,"messageId":"unusedVar","endLine":26,"endColumn":21},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'mockConceptNodes' is defined but never used.","line":27,"column":3,"nodeType":null,"messageId":"unusedVar","endLine":27,"endColumn":19},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'mockHypotheses' is defined but never used.","line":28,"column":3,"nodeType":null,"messageId":"unusedVar","endLine":28,"endColumn":17},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'Zap' is defined but never used.","line":46,"column":3,"nodeType":null,"messageId":"unusedVar","endLine":46,"endColumn":6},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'CheckCircle2' is defined but never used.","line":49,"column":3,"nodeType":null,"messageId":"unusedVar","endLine":49,"endColumn":15},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":63,"column":66,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":63,"endColumn":69,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2072,2075],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2072,2075],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":187,"column":47,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":187,"endColumn":50,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[7035,7038],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[7035,7038],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":295,"column":39,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":295,"endColumn":42,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[10772,10775],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[10772,10775],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":11,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\n\nimport { useState, useEffect } from 'react';\nimport { Sidebar } from '@/components/sidebar';\nimport { ProjectCard } from '@/components/project-card';\nimport { AgentPipeline } from '@/components/agent-pipeline';\nimport { QualityMetricsChart } from '@/components/quality-metrics-chart';\nimport { CitationChart } from '@/components/citation-chart';\nimport { WordCountTrend } from '@/components/word-count-trend';\nimport { ConceptNetwork } from '@/components/concept-network';\nimport { HypothesisTable } from '@/components/hypothesis-table';\nimport { DocumentTypeChart } from '@/components/document-type-chart';\nimport { FileUpload } from '@/components/file-upload';\nimport { NewProjectDialog } from '@/components/new-project-dialog';\nimport { ProjectDetailsView } from '@/components/project-details-view';\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';\nimport { Button } from '@/components/ui/button';\nimport { Badge } from '@/components/ui/badge';\nimport { Progress } from '@/components/ui/progress';\nimport { useProjects } from '@/hooks/use-projects';\nimport { useAnalytics } from '@/hooks/use-analytics';\nimport {\n mockAgents,\n mockQualityMetrics,\n mockCitationData,\n mockWordCountTrend,\n mockConceptNodes,\n mockHypotheses\n} from '@/lib/mock-data';\nimport {\n Sparkles,\n FolderOpen,\n BarChart3,\n Settings as SettingsIcon,\n Search,\n Filter,\n Download,\n Upload,\n Trash2,\n Archive,\n Bell,\n User,\n Lock,\n Palette,\n Globe,\n Zap,\n TrendingUp,\n Clock,\n CheckCircle2,\n AlertCircle,\n Loader2,\n RefreshCw,\n FileText\n} from 'lucide-react';\n\ntype TabType = 'dashboard' | 'projects' | 'analytics' | 'settings';\n\nexport default function Home() {\n const [activeTab, setActiveTab] = useState<TabType>('dashboard');\n const [isNewProjectOpen, setIsNewProjectOpen] = useState(false);\n const { projects, loading, error, refetch } = useProjects();\n const [selectedProjectId, setSelectedProjectId] = useState<string | null>(null);\n const [selectedProjectData, setSelectedProjectData] = useState<any>(null);\n const [dashboardView, setDashboardView] = useState<'list' | 'details'>('list');\n\n // Fetch selected project details with polling\n useEffect(() => {\n if (!selectedProjectId) return;\n\n const fetchDetails = () => {\n fetch(`/api/projects/${selectedProjectId}`)\n .then(res => res.json())\n .then(data => setSelectedProjectData(data))\n .catch(console.error);\n };\n\n fetchDetails();\n\n // Poll only if processing\n const interval = setInterval(() => {\n if (selectedProjectData?.status === 'processing') {\n fetchDetails();\n }\n }, 3000);\n\n return () => clearInterval(interval);\n }, [selectedProjectId, selectedProjectData?.status]);\n\n // Auto-select first project - REMOVED to show list first\n // useEffect(() => {\n // if (projects.length > 0 && !selectedProjectId) {\n // setSelectedProjectId(projects[0].id);\n // }\n // }, [projects, selectedProjectId]);\n\n const handleProjectClick = (projectId: string) => {\n setSelectedProjectId(projectId);\n setDashboardView('details');\n };\n\n const handleBackToDashboard = () => {\n setDashboardView('list');\n setSelectedProjectId(null);\n setSelectedProjectData(null);\n };\n\n // Dashboard Content\n const DashboardContent = () => (\n <div className=\"space-y-8\">\n {/* Dashboard Views */}\n {dashboardView === 'list' ? (\n <>\n {/* Header with Gradient */}\n <div className=\"relative overflow-hidden rounded-2xl bg-gradient-to-br from-primary/10 via-secondary/10 to-chart-3/10 p-8 border animate-fadeIn\">\n <div className=\"absolute top-0 right-0 w-64 h-64 bg-primary/5 rounded-full blur-3xl\" />\n <div className=\"absolute bottom-0 left-0 w-64 h-64 bg-secondary/5 rounded-full blur-3xl\" />\n <div className=\"relative z-10\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3 mb-2\">\n <Sparkles className=\"w-8 h-8 text-primary\" />\n <h1 className=\"text-4xl font-serif font-bold text-foreground\">\n Dashboard\n </h1>\n </div>\n <Button variant=\"outline\" size=\"sm\" onClick={refetch} className=\"gap-2\">\n <RefreshCw className=\"w-4 h-4\" />\n Refresh\n </Button>\n </div>\n <p className=\"text-muted-foreground text-lg\">\n Manage your AI-powered research paper generation projects\n </p>\n </div>\n </div>\n\n {/* Projects Grid */}\n <section className=\"animate-fadeIn\" style={{ animationDelay: '0.2s' }}>\n <h2 className=\"text-2xl font-serif font-semibold mb-6 flex items-center gap-2\">\n <span className=\"w-1 h-8 bg-primary rounded-full\" />\n Your Projects\n </h2>\n\n {loading && (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"w-8 h-8 animate-spin text-primary\" />\n <span className=\"ml-3 text-muted-foreground\">Loading projects...</span>\n </div>\n )}\n\n {error && (\n <Card className=\"border-destructive/50 bg-destructive/5\">\n <CardContent className=\"p-6\">\n <div className=\"flex items-center gap-3\">\n <AlertCircle className=\"w-5 h-5 text-destructive\" />\n <div>\n <p className=\"font-semibold text-destructive\">Error loading projects</p>\n <p className=\"text-sm text-muted-foreground\">{error}</p>\n </div>\n </div>\n </CardContent>\n </Card>\n )}\n\n {!loading && !error && projects.length === 0 && (\n <Card>\n <CardContent className=\"p-12 text-center\">\n <FolderOpen className=\"w-16 h-16 mx-auto mb-4 text-muted-foreground\" />\n <h3 className=\"text-xl font-semibold mb-2\">No projects yet</h3>\n <p className=\"text-muted-foreground mb-4\">\n Create your first project to get started with AI research paper generation\n </p>\n <Button onClick={() => setIsNewProjectOpen(true)}>\n <Upload className=\"w-4 h-4 mr-2\" />\n Create Project\n </Button>\n </CardContent>\n </Card>\n )}\n\n {!loading && !error && projects.length > 0 && (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\">\n {projects.map((project, index) => {\n const displayProject = {\n id: project.id,\n title: project.name,\n description: project.description || '',\n status: project.status as any,\n lastUpdated: new Date(project.updatedAt),\n documentCount: project._count?.documents || 0,\n progress: project.progress,\n };\n\n return (\n <div key={project.id} style={{ animationDelay: `${0.3 + index * 0.1}s` }}>\n <ProjectCard\n project={displayProject}\n onClick={() => handleProjectClick(project.id)}\n />\n </div>\n );\n })}\n </div>\n )}\n </section>\n </>\n ) : (\n <ProjectDetailsView\n project={selectedProjectData}\n onBack={handleBackToDashboard}\n onRefresh={() => {\n const fetchDetails = () => {\n fetch(`/api/projects/${selectedProjectId}`)\n .then(res => res.json())\n .then(data => setSelectedProjectData(data))\n .catch(console.error);\n };\n fetchDetails();\n }}\n />\n )}\n </div>\n );\n\n // Projects Content\n const ProjectsContent = () => (\n <div className=\"space-y-6 animate-fadeIn\">\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-4xl font-serif font-bold mb-2 flex items-center gap-3\">\n <FolderOpen className=\"w-10 h-10 text-primary\" />\n Projects\n </h1>\n <p className=\"text-muted-foreground\">Manage all your research paper projects</p>\n </div>\n <Button className=\"gap-2\">\n <Upload className=\"w-4 h-4\" />\n New Project\n </Button>\n </div>\n\n {/* Search and Filter */}\n <Card>\n <CardContent className=\"p-4\">\n <div className=\"flex gap-4\">\n <div className=\"flex-1 relative\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground\" />\n <input\n type=\"text\"\n placeholder=\"Search projects...\"\n className=\"w-full pl-10 pr-4 py-2 bg-background border rounded-lg focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n </div>\n <Button variant=\"outline\" className=\"gap-2\">\n <Filter className=\"w-4 h-4\" />\n Filter\n </Button>\n </div>\n </CardContent>\n </Card>\n\n {/* Projects List */}\n <div className=\"grid grid-cols-1 gap-4\">\n {loading && (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"w-8 h-8 animate-spin text-primary\" />\n <span className=\"ml-3 text-muted-foreground\">Loading projects...</span>\n </div>\n )}\n\n {error && (\n <Card className=\"border-destructive/50 bg-destructive/5\">\n <CardContent className=\"p-6\">\n <p className=\"text-destructive\">Error loading projects: {error}</p>\n </CardContent>\n </Card>\n )}\n\n {!loading && !error && projects.length === 0 && (\n <Card>\n <CardContent className=\"p-12 text-center\">\n <p className=\"text-muted-foreground mb-4\">No projects found.</p>\n <Button onClick={() => setIsNewProjectOpen(true)}>\n Create Project\n </Button>\n </CardContent>\n </Card>\n )}\n\n {!loading && !error && projects.map((project, index) => {\n const displayProject = {\n id: project.id,\n title: project.name,\n description: project.description || '',\n status: project.status as any,\n lastUpdated: new Date(project.updatedAt),\n documentCount: project._count?.documents || 0,\n progress: project.progress,\n };\n\n return (\n <Card key={project.id} className=\"hover-lift transition-smooth animate-slideIn\" style={{ animationDelay: `${index * 0.1}s` }}>\n <CardContent className=\"p-6\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-3 mb-2\">\n <h3 className=\"text-xl font-semibold\">{displayProject.title}</h3>\n <Badge variant={displayProject.status === 'completed' ? 'default' : displayProject.status === 'processing' ? 'secondary' : 'outline'}>\n {displayProject.status}\n </Badge>\n </div>\n <p className=\"text-muted-foreground mb-4\">{displayProject.description}</p>\n\n <div className=\"grid grid-cols-3 gap-4 mb-4\">\n <div className=\"flex items-center gap-2 text-sm\">\n <Clock className=\"w-4 h-4 text-muted-foreground\" />\n <span className=\"font-mono\">{displayProject.lastUpdated.toLocaleDateString()}</span>\n </div>\n <div className=\"flex items-center gap-2 text-sm\">\n <FolderOpen className=\"w-4 h-4 text-muted-foreground\" />\n <span className=\"font-mono\">{displayProject.documentCount} documents</span>\n </div>\n <div className=\"flex items-center gap-2 text-sm\">\n <TrendingUp className=\"w-4 h-4 text-muted-foreground\" />\n <span className=\"font-mono\">{displayProject.progress}% complete</span>\n </div>\n </div>\n\n <Progress value={displayProject.progress} className=\"h-2\" />\n </div>\n\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\">\n <Download className=\"w-4 h-4\" />\n </Button>\n <Button variant=\"outline\" size=\"sm\">\n <Archive className=\"w-4 h-4\" />\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={() => {\n if (confirm('Are you sure you want to delete this project?')) {\n fetch(`/api/projects/${project.id}`, { method: 'DELETE' })\n .then(() => refetch());\n }\n }}>\n <Trash2 className=\"w-4 h-4\" />\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n )\n })}\n </div>\n </div>\n );\n\n // Analytics Content\n const AnalyticsContent = () => {\n const { data: analytics, loading: analyticsLoading, error: analyticsError } = useAnalytics();\n\n if (analyticsLoading) {\n return (\n <div className=\"flex items-center justify-center h-96\">\n <div className=\"flex flex-col items-center gap-4\">\n <Loader2 className=\"w-8 h-8 text-primary animate-spin\" />\n <p className=\"text-muted-foreground\">Loading analytics...</p>\n </div>\n </div>\n );\n }\n\n if (analyticsError || !analytics) {\n return (\n <div className=\"flex items-center justify-center h-96\">\n <div className=\"flex flex-col items-center gap-4\">\n <AlertCircle className=\"w-8 h-8 text-destructive\" />\n <p className=\"text-destructive\">Failed to load analytics</p>\n <Button variant=\"outline\" onClick={() => window.location.reload()}>Retry</Button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 animate-fadeIn\">\n {/* Header */}\n <div>\n <h1 className=\"text-4xl font-serif font-bold mb-2 flex items-center gap-3\">\n <BarChart3 className=\"w-10 h-10 text-primary\" />\n Analytics\n </h1>\n <p className=\"text-muted-foreground\">Comprehensive insights across all projects</p>\n </div>\n\n {/* Stats Grid */}\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6\">\n <Card className=\"animate-scaleIn\">\n <CardHeader className=\"pb-3\">\n <CardDescription>Total Projects</CardDescription>\n <CardTitle className=\"text-4xl font-mono\">{analytics.totalProjects}</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <FolderOpen className=\"w-4 h-4 text-primary\" />\n <span>Active research</span>\n </div>\n </CardContent>\n </Card>\n\n <Card className=\"animate-scaleIn\" style={{ animationDelay: '0.1s' }}>\n <CardHeader className=\"pb-3\">\n <CardDescription>Total Documents</CardDescription>\n <CardTitle className=\"text-4xl font-mono\">{analytics.totalDocuments}</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <FileText className=\"w-4 h-4 text-chart-2\" />\n <span>Processed files</span>\n </div>\n </CardContent>\n </Card>\n\n <Card className=\"animate-scaleIn\" style={{ animationDelay: '0.2s' }}>\n <CardHeader className=\"pb-3\">\n <CardDescription>Avg Quality Score</CardDescription>\n <CardTitle className=\"text-4xl font-mono\">{analytics.avgQuality}%</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Sparkles className=\"w-4 h-4 text-chart-4\" />\n <span>Based on hypotheses</span>\n </div>\n </CardContent>\n </Card>\n\n <Card className=\"animate-scaleIn\" style={{ animationDelay: '0.3s' }}>\n <CardHeader className=\"pb-3\">\n <CardDescription>Research Velocity</CardDescription>\n <CardTitle className=\"text-4xl font-mono\">High</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Clock className=\"w-4 h-4 text-secondary\" />\n <span>Avg per paper</span>\n </div>\n </CardContent>\n </Card>\n </div>\n\n {/* Charts */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n <CitationChart data={analytics.citationData} />\n <WordCountTrend data={analytics.wordCountTrend} />\n <QualityMetricsChart metrics={analytics.qualityMetrics} />\n <DocumentTypeChart />\n <ConceptNetwork nodes={analytics.conceptNodes} />\n </div>\n </div>\n );\n };\n\n // Settings Content\n const SettingsContent = () => (\n <div className=\"space-y-6 animate-fadeIn max-w-4xl\">\n {/* Header */}\n <div>\n <h1 className=\"text-4xl font-serif font-bold mb-2 flex items-center gap-3\">\n <SettingsIcon className=\"w-10 h-10 text-primary\" />\n Settings\n </h1>\n <p className=\"text-muted-foreground\">Customize your research assistant</p>\n </div>\n\n {/* Profile Settings */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <User className=\"w-5 h-5\" />\n Profile\n </CardTitle>\n <CardDescription>Manage your account information</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"text-sm font-medium mb-2 block\">Full Name</label>\n <input type=\"text\" placeholder=\"John Doe\" className=\"w-full px-3 py-2 bg-background border rounded-lg\" />\n </div>\n <div>\n <label className=\"text-sm font-medium mb-2 block\">Email</label>\n <input type=\"email\" placeholder=\"john@example.com\" className=\"w-full px-3 py-2 bg-background border rounded-lg\" />\n </div>\n </div>\n <Button>Save Changes</Button>\n </CardContent>\n </Card>\n\n {/* Appearance */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Palette className=\"w-5 h-5\" />\n Appearance\n </CardTitle>\n <CardDescription>Customize the look and feel</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium mb-2 block\">Theme</label>\n <div className=\"flex gap-4\">\n <Button variant=\"outline\" className=\"flex-1\">Light</Button>\n <Button variant=\"outline\" className=\"flex-1\">Dark</Button>\n <Button variant=\"outline\" className=\"flex-1\">System</Button>\n </div>\n </div>\n </CardContent>\n </Card>\n\n {/* Notifications */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Bell className=\"w-5 h-5\" />\n Notifications\n </CardTitle>\n <CardDescription>Configure notification preferences</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {['Project completion', 'Agent errors', 'Weekly summary'].map((item) => (\n <div key={item} className=\"flex items-center justify-between\">\n <span className=\"text-sm\">{item}</span>\n <input type=\"checkbox\" className=\"w-4 h-4\" defaultChecked />\n </div>\n ))}\n </CardContent>\n </Card>\n\n {/* API Settings */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Globe className=\"w-5 h-5\" />\n API Configuration\n </CardTitle>\n <CardDescription>Configure AI model settings</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium mb-2 block\">API Provider</label>\n <select className=\"w-full px-3 py-2 bg-background border rounded-lg\">\n <option>Gemini API</option>\n <option>OpenAI</option>\n <option>Anthropic</option>\n </select>\n </div>\n <div>\n <label className=\"text-sm font-medium mb-2 block\">API Key</label>\n <input type=\"password\" placeholder=\"ΓÇóΓÇóΓÇóΓÇóΓÇóΓÇóΓÇóΓÇóΓÇóΓÇóΓÇóΓÇóΓÇóΓÇóΓÇóΓÇó\" className=\"w-full px-3 py-2 bg-background border rounded-lg\" />\n </div>\n <Button>Update API Settings</Button>\n </CardContent>\n </Card>\n\n {/* Security */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Lock className=\"w-5 h-5\" />\n Security\n </CardTitle>\n <CardDescription>Manage security settings</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <Button variant=\"outline\" className=\"w-full justify-start\">\n Change Password\n </Button>\n <Button variant=\"outline\" className=\"w-full justify-start\">\n Two-Factor Authentication\n </Button>\n <Button variant=\"destructive\" className=\"w-full justify-start\">\n Delete Account\n </Button>\n </CardContent>\n </Card>\n </div>\n );\n\n return (\n <div className=\"flex h-screen bg-background overflow-hidden\">\n <Sidebar\n onNewProject={() => setIsNewProjectOpen(true)}\n activeTab={activeTab}\n onTabChange={setActiveTab}\n />\n\n <main className=\"flex-1 overflow-auto\">\n <div className=\"p-8\">\n {activeTab === 'dashboard' && <DashboardContent />}\n {activeTab === 'projects' && <ProjectsContent />}\n {activeTab === 'analytics' && <AnalyticsContent />}\n {activeTab === 'settings' && <SettingsContent />}\n\n <div className=\"h-8\" />\n </div>\n </main>\n\n {/* New Project Dialog */}\n <NewProjectDialog\n open={isNewProjectOpen}\n onOpenChange={setIsNewProjectOpen}\n />\n </div>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\agent-pipeline.tsx","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":13,"column":17,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":13,"endColumn":20,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[491,494],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[491,494],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'status' is defined but never used.","line":26,"column":33,"nodeType":null,"messageId":"unusedVar","endLine":26,"endColumn":39},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":96,"column":83,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":96,"endColumn":86,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[4380,4383],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[4380,4383],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":102,"column":91,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":102,"endColumn":94,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[4835,4838],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[4835,4838],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\r\n\r\nimport { useState } from 'react';\r\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';\r\nimport { Badge } from '@/components/ui/badge';\r\nimport { Agent } from '@/lib/types';\r\nimport { Clock, CheckCircle2, Loader2, XCircle, Circle, ChevronDown, ChevronUp, Terminal, Activity } from 'lucide-react';\r\nimport { cn } from '@/lib/utils';\r\n\r\ninterface AgentPipelineProps {\r\n status?: string;\r\n progress?: number;\r\n agentRuns?: any[];\r\n agents?: Agent[]; // Fallback for mock data\r\n}\r\n\r\nconst DEFAULT_AGENTS: Agent[] = [\r\n { id: 'reader', name: 'Reader Agent', status: 'pending' },\r\n { id: 'summarizer', name: 'Summarizer Agent', status: 'pending' },\r\n { id: 'graph', name: 'Graph Agent', status: 'pending' },\r\n { id: 'hypothesis', name: 'Hypothesis Agent', status: 'pending' },\r\n { id: 'experiment', name: 'Experiment Agent', status: 'pending' },\r\n { id: 'writer', name: 'Paper Writer Agent', status: 'pending' },\r\n];\r\n\r\nexport function AgentPipeline({ status, progress, agentRuns, agents: propAgents }: AgentPipelineProps) {\r\n const [expandedAgent, setExpandedAgent] = useState<string | null>(null);\r\n\r\n // Merge backend data with default agents\r\n const displayAgents: Agent[] = agentRuns ? DEFAULT_AGENTS.map(defaultAgent => {\r\n const run = agentRuns.find(r => r.agentName === defaultAgent.id);\r\n if (run) {\r\n return {\r\n ...defaultAgent,\r\n status: run.status as Agent['status'],\r\n output: run.output ? JSON.parse(run.output) : null,\r\n executionTime: run.executionTime,\r\n error: run.error\r\n };\r\n }\r\n return defaultAgent;\r\n }) : (propAgents || DEFAULT_AGENTS);\r\n\r\n const getStatusIcon = (status: string) => {\r\n switch (status) {\r\n case 'completed':\r\n return <CheckCircle2 className=\"w-5 h-5 text-primary\" />;\r\n case 'running':\r\n case 'processing':\r\n return <Loader2 className=\"w-5 h-5 text-chart-3 animate-spin\" />;\r\n case 'error':\r\n return <XCircle className=\"w-5 h-5 text-destructive\" />;\r\n default:\r\n return <Circle className=\"w-5 h-5 text-muted-foreground/30\" />;\r\n }\r\n };\r\n\r\n const getStatusBadge = (status: string) => {\r\n switch (status) {\r\n case 'completed':\r\n return <Badge variant=\"default\" className=\"bg-primary/20 text-primary hover:bg-primary/30 border-primary/20\">Completed</Badge>;\r\n case 'running':\r\n case 'processing':\r\n return (\r\n <Badge variant=\"secondary\" className=\"bg-chart-3/20 text-chart-3 hover:bg-chart-3/30 border-chart-3/20 animate-pulse gap-1\">\r\n <Activity className=\"w-3 h-3 animate-bounce\" /> Processing\r\n </Badge>\r\n );\r\n case 'error':\r\n return <Badge variant=\"destructive\">Error</Badge>;\r\n default:\r\n return <Badge variant=\"outline\" className=\"text-muted-foreground\">Pending</Badge>;\r\n }\r\n };\r\n\r\n const toggleExpand = (agentId: string) => {\r\n setExpandedAgent(expandedAgent === agentId ? null : agentId);\r\n };\r\n\r\n return (\r\n <Card className=\"shadow-premium animate-fadeIn overflow-hidden border-muted/40\">\r\n <CardHeader className=\"bg-muted/20 pb-4\">\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <CardTitle className=\"flex items-center gap-2\">\r\n <Terminal className=\"w-5 h-5 text-primary\" />\r\n Agent Pipeline\r\n </CardTitle>\r\n <CardDescription>Real-time multi-agent workflow execution</CardDescription>\r\n </div>\r\n {/* Overall Progress */}\r\n <div className=\"flex items-center gap-2\">\r\n <div className=\"text-right mr-2\">\r\n <p className=\"text-xs font-medium text-muted-foreground\">Total Progress</p>\r\n <p className=\"text-lg font-bold font-mono text-primary\">\r\n {Math.round(progress || (displayAgents.filter((a: any) => a.status === 'completed').length / displayAgents.length) * 100)}%\r\n </p>\r\n </div>\r\n <div className=\"h-10 w-1 bg-muted rounded-full overflow-hidden\">\r\n <div\r\n className=\"w-full bg-primary transition-all duration-500 ease-out\"\r\n style={{ height: `${progress || (displayAgents.filter((a: any) => a.status === 'completed').length / displayAgents.length) * 100}%` }}\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </CardHeader>\r\n <CardContent className=\"p-0\">\r\n <div className=\"divide-y divide-border/50\">\r\n {displayAgents.map((agent, index) => {\r\n const isExpanded = expandedAgent === agent.id;\r\n const hasOutput = agent.output || agent.status === 'completed';\r\n const isRunning = agent.status === 'running' || agent.status === 'processing';\r\n\r\n return (\r\n <div key={agent.id} className={cn(\r\n \"transition-all duration-300\",\r\n isRunning ? \"bg-primary/5\" : \"hover:bg-muted/20\"\r\n )}>\r\n <div\r\n className=\"p-4 flex items-center gap-4 cursor-pointer\"\r\n onClick={() => hasOutput && toggleExpand(agent.id)}\r\n >\r\n {/* Status Icon with Connector Line */}\r\n <div className=\"relative flex flex-col items-center\">\r\n {index > 0 && (\r\n <div className={cn(\r\n \"absolute -top-8 w-0.5 h-8 -z-10\",\r\n displayAgents[index - 1].status === 'completed' ? \"bg-primary/50\" : \"bg-muted\"\r\n )} />\r\n )}\r\n <div className={cn(\r\n \"relative z-10 rounded-full p-1 bg-background border-2 transition-colors duration-300\",\r\n agent.status === 'completed' ? \"border-primary\" :\r\n isRunning ? \"border-chart-3 shadow-[0_0_10px_rgba(0,0,0,0.1)] shadow-chart-3/30\" : \"border-muted\"\r\n )}>\r\n {getStatusIcon(agent.status)}\r\n </div>\r\n </div>\r\n\r\n {/* Agent Info */}\r\n <div className=\"flex-1 min-w-0\">\r\n <div className=\"flex items-center justify-between mb-1\">\r\n <h4 className={cn(\r\n \"font-medium truncate\",\r\n agent.status === 'completed' ? \"text-foreground\" : \"text-muted-foreground\"\r\n )}>\r\n {agent.name}\r\n </h4>\r\n {getStatusBadge(agent.status)}\r\n </div>\r\n\r\n <div className=\"flex items-center gap-4 text-xs text-muted-foreground\">\r\n {agent.executionTime && (\r\n <span className=\"flex items-center gap-1 font-mono\">\r\n <Clock className=\"w-3 h-3\" />\r\n {agent.executionTime}s\r\n </span>\r\n )}\r\n {hasOutput && (\r\n <span className=\"text-primary/80 group-hover:text-primary transition-colors\">\r\n {isExpanded ? 'Click to collapse logs' : 'Click to view logs'}\r\n </span>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {hasOutput && (\r\n <div className=\"text-muted-foreground\">\r\n {isExpanded ? <ChevronUp className=\"w-4 h-4\" /> : <ChevronDown className=\"w-4 h-4\" />}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Expanded Logs */}\r\n <div className={cn(\r\n \"grid transition-all duration-300 ease-in-out bg-black/5 dark:bg-black/20\",\r\n isExpanded ? \"grid-rows-[1fr] opacity-100\" : \"grid-rows-[0fr] opacity-0\"\r\n )}>\r\n <div className=\"overflow-hidden\">\r\n <div className=\"p-4 pt-0\">\r\n <div className=\"mt-2 rounded-md border bg-card p-4 font-mono text-xs shadow-inner max-h-[300px] overflow-y-auto custom-scrollbar\">\r\n <div className=\"flex items-center gap-2 mb-2 text-muted-foreground border-b pb-2\">\r\n <Terminal className=\"w-3 h-3\" />\r\n <span>Agent Output Log</span>\r\n </div>\r\n <pre className=\"whitespace-pre-wrap text-foreground/90 leading-relaxed\">\r\n {typeof agent.output === 'string'\r\n ? agent.output\r\n : JSON.stringify(agent.output, null, 2)}\r\n </pre>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </CardContent>\r\n </Card>\r\n );\r\n}\r\n\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\citation-chart.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\concept-network.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'nextNode' is assigned a value but never used.","line":94,"column":43,"nodeType":null,"messageId":"unusedVar","endLine":94,"endColumn":51}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\r\n\r\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';\r\nimport { Badge } from '@/components/ui/badge';\r\n\r\ninterface ConceptNode {\r\n id: string;\r\n label: string;\r\n importance: number;\r\n cluster: number;\r\n}\r\n\r\ninterface ConceptNetworkProps {\r\n nodes: ConceptNode[];\r\n}\r\n\r\nexport function ConceptNetwork({ nodes }: ConceptNetworkProps) {\r\n const clusters = Array.from(new Set(nodes.map(n => n.cluster)));\r\n const clusterColors = [\r\n 'bg-chart-1',\r\n 'bg-chart-2',\r\n 'bg-chart-3',\r\n 'bg-primary',\r\n 'bg-secondary',\r\n ];\r\n\r\n const getNodeSize = (importance: number) => {\r\n if (importance > 80) return 'w-16 h-16 text-sm';\r\n if (importance > 60) return 'w-14 h-14 text-xs';\r\n if (importance > 40) return 'w-12 h-12 text-xs';\r\n return 'w-10 h-10 text-xs';\r\n };\r\n\r\n return (\r\n <Card className=\"shadow-premium animate-fadeIn\">\r\n <CardHeader>\r\n <CardTitle>Concept Network</CardTitle>\r\n <CardDescription>Research concept relationships and clusters</CardDescription>\r\n </CardHeader>\r\n <CardContent>\r\n {/* Legend */}\r\n <div className=\"flex flex-wrap gap-2 mb-6\">\r\n {clusters.map((cluster, idx) => (\r\n <Badge key={cluster} variant=\"outline\" className=\"gap-2\">\r\n <div className={`w-3 h-3 rounded-full ${clusterColors[idx % clusterColors.length]}`} />\r\n Cluster {cluster}\r\n </Badge>\r\n ))}\r\n </div>\r\n\r\n {/* Network Visualization */}\r\n <div className=\"relative h-96 bg-muted/20 rounded-lg border overflow-hidden\">\r\n <div className=\"absolute inset-0 flex items-center justify-center p-8\">\r\n <div className=\"relative w-full h-full\">\r\n {nodes.map((node, index) => {\r\n // Circular layout\r\n const angle = (index / nodes.length) * 2 * Math.PI;\r\n const radius = 35; // percentage\r\n const x = 50 + radius * Math.cos(angle);\r\n const y = 50 + radius * Math.sin(angle);\r\n\r\n return (\r\n <div\r\n key={node.id}\r\n className=\"absolute transform -translate-x-1/2 -translate-y-1/2 animate-scaleIn\"\r\n style={{\r\n left: `${x}%`,\r\n top: `${y}%`,\r\n animationDelay: `${index * 0.05}s`,\r\n }}\r\n >\r\n <div\r\n className={`\r\n ${getNodeSize(node.importance)}\r\n ${clusterColors[node.cluster % clusterColors.length]}\r\n rounded-full flex items-center justify-center\r\n font-semibold text-white shadow-lg\r\n hover:scale-110 transition-transform cursor-pointer\r\n hover:shadow-xl\r\n `}\r\n title={`${node.label} (Importance: ${node.importance})`}\r\n >\r\n <span className=\"text-center px-1 truncate\">\r\n {node.label.split(' ')[0]}\r\n </span>\r\n </div>\r\n </div>\r\n );\r\n })}\r\n\r\n {/* Connection lines (simplified) */}\r\n <svg className=\"absolute inset-0 w-full h-full pointer-events-none opacity-20\">\r\n {nodes.map((node, i) => {\r\n const nextNode = nodes[(i + 1) % nodes.length];\r\n const angle1 = (i / nodes.length) * 2 * Math.PI;\r\n const angle2 = ((i + 1) / nodes.length) * 2 * Math.PI;\r\n const radius = 35;\r\n\r\n const x1 = 50 + radius * Math.cos(angle1);\r\n const y1 = 50 + radius * Math.sin(angle1);\r\n const x2 = 50 + radius * Math.cos(angle2);\r\n const y2 = 50 + radius * Math.sin(angle2);\r\n\r\n return (\r\n <line\r\n key={`line-${i}`}\r\n x1={`${x1}%`}\r\n y1={`${y1}%`}\r\n x2={`${x2}%`}\r\n y2={`${y2}%`}\r\n stroke=\"currentColor\"\r\n strokeWidth=\"1\"\r\n className=\"text-border\"\r\n />\r\n );\r\n })}\r\n </svg>\r\n </div>\r\n </div>\r\n\r\n {/* Center label */}\r\n <div className=\"absolute inset-0 flex items-center justify-center pointer-events-none\">\r\n <div className=\"bg-background/80 backdrop-blur-sm rounded-full w-24 h-24 flex items-center justify-center border-2 border-primary/20\">\r\n <span className=\"text-xs font-semibold text-center text-muted-foreground\">\r\n Research<br />Concepts\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Stats */}\r\n <div className=\"grid grid-cols-3 gap-4 mt-6\">\r\n <div className=\"text-center p-3 bg-muted/30 rounded-lg\">\r\n <p className=\"text-2xl font-bold font-mono text-primary\">{nodes.length}</p>\r\n <p className=\"text-xs text-muted-foreground mt-1\">Concepts</p>\r\n </div>\r\n <div className=\"text-center p-3 bg-muted/30 rounded-lg\">\r\n <p className=\"text-2xl font-bold font-mono text-chart-2\">{clusters.length}</p>\r\n <p className=\"text-xs text-muted-foreground mt-1\">Clusters</p>\r\n </div>\r\n <div className=\"text-center p-3 bg-muted/30 rounded-lg\">\r\n <p className=\"text-2xl font-bold font-mono text-chart-3\">\r\n {Math.round(nodes.reduce((sum, n) => sum + n.importance, 0) / nodes.length)}\r\n </p>\r\n <p className=\"text-xs text-muted-foreground mt-1\">Avg Importance</p>\r\n </div>\r\n </div>\r\n </CardContent>\r\n </Card>\r\n );\r\n}\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\document-type-chart.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\file-upload.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\hypothesis-table.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\math-renderer.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'parts' is assigned a value but never used.","line":18,"column":15,"nodeType":null,"messageId":"unusedVar","endLine":18,"endColumn":20},{"ruleId":"prefer-const","severity":2,"message":"'currentIndex' is never reassigned. Use 'const' instead.","line":19,"column":13,"nodeType":"Identifier","messageId":"useConst","endLine":19,"endColumn":25,"fix":{"range":[526,547],"text":"const currentIndex = 0;"}},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'currentIndex' is assigned a value but never used.","line":19,"column":13,"nodeType":null,"messageId":"unusedVar","endLine":19,"endColumn":25},{"ruleId":"prefer-const","severity":2,"message":"'key' is never reassigned. Use 'const' instead.","line":20,"column":13,"nodeType":"Identifier","messageId":"useConst","endLine":20,"endColumn":16,"fix":{"range":[557,569],"text":"const key = 0;"}},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'key' is assigned a value but never used.","line":20,"column":13,"nodeType":null,"messageId":"unusedVar","endLine":20,"endColumn":16},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'inlineMathRegex' is assigned a value but never used.","line":24,"column":15,"nodeType":null,"messageId":"unusedVar","endLine":24,"endColumn":30},{"ruleId":"prefer-const","severity":2,"message":"'textContent' is never reassigned. Use 'const' instead.","line":75,"column":21,"nodeType":"Identifier","messageId":"useConst","endLine":75,"endColumn":32,"fix":{"range":[2514,2548],"text":"const textContent = segment.content;"}}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":3,"fixableWarningCount":0,"source":"'use client';\r\n\r\nimport React from 'react';\r\nimport 'katex/dist/katex.min.css';\r\nimport { InlineMath, BlockMath } from 'react-katex';\r\n\r\ninterface MathRendererProps {\r\n content: string;\r\n className?: string;\r\n}\r\n\r\n/**\r\n * Renders text with LaTeX mathematical formulas\r\n * Supports inline math: $formula$ and block math: $$formula$$\r\n */\r\nexport const MathRenderer: React.FC<MathRendererProps> = ({ content, className = '' }) => {\r\n const renderContent = () => {\r\n const parts: React.ReactNode[] = [];\r\n let currentIndex = 0;\r\n let key = 0;\r\n\r\n // Regular expressions for block and inline math\r\n const blockMathRegex = /\\$\\$(.*?)\\$\\$/gs;\r\n const inlineMathRegex = /\\$(.*?)\\$/g;\r\n\r\n // First, find all block math sections\r\n const blockMatches: Array<{ start: number; end: number; formula: string }> = [];\r\n let match;\r\n\r\n while ((match = blockMathRegex.exec(content)) !== null) {\r\n blockMatches.push({\r\n start: match.index,\r\n end: match.index + match[0].length,\r\n formula: match[1],\r\n });\r\n }\r\n\r\n // Process content\r\n let lastEnd = 0;\r\n const segments: Array<{ type: 'text' | 'block' | 'inline'; content: string; start: number; end: number }> = [];\r\n\r\n // Add block math segments\r\n blockMatches.forEach((blockMatch) => {\r\n if (blockMatch.start > lastEnd) {\r\n segments.push({\r\n type: 'text',\r\n content: content.substring(lastEnd, blockMatch.start),\r\n start: lastEnd,\r\n end: blockMatch.start,\r\n });\r\n }\r\n segments.push({\r\n type: 'block',\r\n content: blockMatch.formula,\r\n start: blockMatch.start,\r\n end: blockMatch.end,\r\n });\r\n lastEnd = blockMatch.end;\r\n });\r\n\r\n // Add remaining text\r\n if (lastEnd < content.length) {\r\n segments.push({\r\n type: 'text',\r\n content: content.substring(lastEnd),\r\n start: lastEnd,\r\n end: content.length,\r\n });\r\n }\r\n\r\n // Process text segments for inline math\r\n const processedSegments: Array<{ type: 'text' | 'block' | 'inline'; content: string }> = [];\r\n segments.forEach((segment) => {\r\n if (segment.type === 'text') {\r\n let textContent = segment.content;\r\n let lastIdx = 0;\r\n let inlineMatch;\r\n const inlineRegex = /\\$(.*?)\\$/g;\r\n\r\n while ((inlineMatch = inlineRegex.exec(textContent)) !== null) {\r\n if (inlineMatch.index > lastIdx) {\r\n processedSegments.push({\r\n type: 'text',\r\n content: textContent.substring(lastIdx, inlineMatch.index),\r\n });\r\n }\r\n processedSegments.push({\r\n type: 'inline',\r\n content: inlineMatch[1],\r\n });\r\n lastIdx = inlineMatch.index + inlineMatch[0].length;\r\n }\r\n\r\n if (lastIdx < textContent.length) {\r\n processedSegments.push({\r\n type: 'text',\r\n content: textContent.substring(lastIdx),\r\n });\r\n }\r\n } else {\r\n processedSegments.push(segment);\r\n }\r\n });\r\n\r\n // Render segments\r\n return processedSegments.map((segment, idx) => {\r\n if (segment.type === 'block') {\r\n return (\r\n <div key={idx} className=\"my-4\">\r\n <BlockMath math={segment.content} />\r\n </div>\r\n );\r\n } else if (segment.type === 'inline') {\r\n return <InlineMath key={idx} math={segment.content} />;\r\n } else {\r\n return <span key={idx}>{segment.content}</span>;\r\n }\r\n });\r\n };\r\n\r\n return <div className={className}>{renderContent()}</div>;\r\n};\r\n\r\n/**\r\n * Simple wrapper for rendering a single formula\r\n */\r\nexport const Formula: React.FC<{ formula: string; block?: boolean }> = ({ formula, block = false }) => {\r\n if (block) {\r\n return (\r\n <div className=\"my-4\">\r\n <BlockMath math={formula} />\r\n </div>\r\n );\r\n }\r\n return <InlineMath math={formula} />;\r\n};\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\new-project-dialog.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'Badge' is defined but never used.","line":6,"column":10,"nodeType":null,"messageId":"unusedVar","endLine":6,"endColumn":15},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'FileText' is defined but never used.","line":7,"column":18,"nodeType":null,"messageId":"unusedVar","endLine":7,"endColumn":26},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'Loader2' is defined but never used.","line":7,"column":42,"nodeType":null,"messageId":"unusedVar","endLine":7,"endColumn":49}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\r\n\r\nimport { useState, useEffect, useRef } from 'react';\r\nimport { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';\r\nimport { Button } from '@/components/ui/button';\r\nimport { Badge } from '@/components/ui/badge';\r\nimport { Upload, FileText, CheckCircle2, Loader2, X, FileType } from 'lucide-react';\r\nimport { cn } from '@/lib/utils';\r\nimport { useToast } from '@/components/ui/toast';\r\n\r\ninterface NewProjectDialogProps {\r\n open: boolean;\r\n onOpenChange: (open: boolean) => void;\r\n onProjectCreated?: () => void;\r\n}\r\n\r\nconst AGENT_STEPS = [\r\n { id: 'reader', label: 'Reader Agent', description: 'Parsing documents' },\r\n { id: 'summarizer', label: 'Summarizer Agent', description: 'Extracting key insights' },\r\n { id: 'graph', label: 'Graph Agent', description: 'Building concept network' },\r\n { id: 'hypothesis', label: 'Hypothesis Agent', description: 'Generating hypotheses' },\r\n { id: 'experiment', label: 'Experiment Agent', description: 'Designing experiments' },\r\n { id: 'writer', label: 'Paper Writer Agent', description: 'Drafting content' },\r\n];\r\n\r\nexport function NewProjectDialog({ open, onOpenChange, onProjectCreated }: NewProjectDialogProps) {\r\n const [projectName, setProjectName] = useState('');\r\n const [description, setDescription] = useState('');\r\n const [files, setFiles] = useState<File[]>([]);\r\n const [isCreating, setIsCreating] = useState(false);\r\n const [dragActive, setDragActive] = useState(false);\r\n const [currentStep, setCurrentStep] = useState<number>(-1);\r\n const fileInputRef = useRef<HTMLInputElement>(null);\r\n const { addToast } = useToast();\r\n\r\n // Reset state when dialog opens/closes\r\n useEffect(() => {\r\n if (!open) {\r\n setProjectName('');\r\n setDescription('');\r\n setFiles([]);\r\n setIsCreating(false);\r\n setCurrentStep(-1);\r\n setDragActive(false);\r\n }\r\n }, [open]);\r\n\r\n // Simulate agent initialization progress\r\n useEffect(() => {\r\n if (isCreating) {\r\n const interval = setInterval(() => {\r\n setCurrentStep(prev => {\r\n if (prev < AGENT_STEPS.length - 1) return prev + 1;\r\n return prev;\r\n });\r\n }, 800);\r\n return () => clearInterval(interval);\r\n }\r\n }, [isCreating]);\r\n\r\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\r\n if (e.target.files) {\r\n addFiles(Array.from(e.target.files));\r\n }\r\n };\r\n\r\n const addFiles = (newFiles: File[]) => {\r\n const validFiles = newFiles.filter(file =>\r\n file.type === 'application/pdf' ||\r\n file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ||\r\n file.name.endsWith('.pdf') ||\r\n file.name.endsWith('.docx')\r\n );\r\n\r\n if (validFiles.length !== newFiles.length) {\r\n addToast('Some files were skipped. Only PDF and DOCX files are allowed.', 'warning');\r\n }\r\n\r\n setFiles(prev => [...prev, ...validFiles]);\r\n };\r\n\r\n const handleDrag = (e: React.DragEvent) => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n if (e.type === 'dragenter' || e.type === 'dragover') {\r\n setDragActive(true);\r\n } else if (e.type === 'dragleave') {\r\n setDragActive(false);\r\n }\r\n };\r\n\r\n const handleDrop = (e: React.DragEvent) => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n setDragActive(false);\r\n if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {\r\n addFiles(Array.from(e.dataTransfer.files));\r\n }\r\n };\r\n\r\n const removeFile = (index: number) => {\r\n setFiles(files.filter((_, i) => i !== index));\r\n };\r\n\r\n const handleCreate = async () => {\r\n if (!projectName.trim() || files.length === 0) return;\r\n\r\n setIsCreating(true);\r\n setCurrentStep(0);\r\n\r\n try {\r\n // Create project\r\n const projectRes = await fetch('/api/projects', {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ name: projectName, description }),\r\n });\r\n\r\n if (!projectRes.ok) throw new Error('Failed to create project');\r\n\r\n const project = await projectRes.json();\r\n\r\n // Upload files\r\n for (const file of files) {\r\n const formData = new FormData();\r\n formData.append('file', file);\r\n formData.append('projectId', project.id);\r\n\r\n const uploadRes = await fetch('/api/upload', {\r\n method: 'POST',\r\n body: formData,\r\n });\r\n\r\n if (!uploadRes.ok) throw new Error(`Failed to upload ${file.name}`);\r\n }\r\n\r\n // Start agent pipeline\r\n await fetch('/api/agents/run', {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ projectId: project.id }),\r\n });\r\n\r\n // Wait a bit to show the animation\r\n await new Promise(resolve => setTimeout(resolve, 2000));\r\n\r\n // Success!\r\n addToast(`Project \"${projectName}\" created successfully!`, 'success');\r\n onOpenChange(false);\r\n onProjectCreated?.();\r\n } catch (error) {\r\n console.error('Error creating project:', error);\r\n addToast('Failed to create project. Please try again.', 'error');\r\n setIsCreating(false);\r\n }\r\n };\r\n\r\n return (\r\n <Dialog open={open} onOpenChange={onOpenChange}>\r\n <DialogContent className=\"sm:max-w-[600px] overflow-hidden\">\r\n <DialogHeader>\r\n <DialogTitle className=\"text-2xl font-serif\">Create New Project</DialogTitle>\r\n <DialogDescription>\r\n Upload research papers and let our multi-agent system analyze them.\r\n </DialogDescription>\r\n </DialogHeader>\r\n\r\n <div className=\"space-y-6 py-4\">\r\n {isCreating ? (\r\n <div className=\"space-y-6 animate-fadeIn\">\r\n <div className=\"text-center space-y-2\">\r\n <div className=\"relative w-16 h-16 mx-auto\">\r\n <div className=\"absolute inset-0 rounded-full border-4 border-muted\" />\r\n <div className=\"absolute inset-0 rounded-full border-4 border-primary border-t-transparent animate-spin\" />\r\n <div className=\"absolute inset-0 flex items-center justify-center\">\r\n <span className=\"text-xs font-bold\">{Math.round(((currentStep + 1) / AGENT_STEPS.length) * 100)}%</span>\r\n </div>\r\n </div>\r\n <h3 className=\"font-semibold text-lg\">Initializing Research Pipeline</h3>\r\n <p className=\"text-muted-foreground text-sm\">Please wait while we set up your agents...</p>\r\n </div>\r\n\r\n <div className=\"grid grid-cols-2 gap-3\">\r\n {AGENT_STEPS.map((step, index) => (\r\n <div\r\n key={step.id}\r\n className={cn(\r\n \"flex items-center gap-3 p-3 rounded-lg border transition-all duration-500\",\r\n index <= currentStep\r\n ? \"bg-primary/5 border-primary/20\"\r\n : \"bg-muted/30 border-transparent opacity-50\"\r\n )}\r\n >\r\n <div className={cn(\r\n \"w-6 h-6 rounded-full flex items-center justify-center text-xs border\",\r\n index < currentStep\r\n ? \"bg-primary text-primary-foreground border-primary\"\r\n : index === currentStep\r\n ? \"border-primary text-primary animate-pulse\"\r\n : \"border-muted-foreground text-muted-foreground\"\r\n )}>\r\n {index < currentStep ? <CheckCircle2 className=\"w-3.5 h-3.5\" /> : index + 1}\r\n </div>\r\n <div>\r\n <div className=\"font-medium text-sm\">{step.label}</div>\r\n <div className=\"text-xs text-muted-foreground\">{step.description}</div>\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"space-y-4 animate-fadeIn\">\r\n {/* Project Name */}\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">\r\n Project Name <span className=\"text-destructive\">*</span>\r\n </label>\r\n <input\r\n type=\"text\"\r\n value={projectName}\r\n onChange={(e) => setProjectName(e.target.value)}\r\n placeholder=\"e.g., Quantum Computing Advances 2024\"\r\n className=\"w-full px-3 py-2 bg-background border rounded-lg focus:outline-none focus:ring-2 focus:ring-ring transition-all\"\r\n autoFocus\r\n />\r\n </div>\r\n\r\n {/* Description */}\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">\r\n Description\r\n </label>\r\n <textarea\r\n value={description}\r\n onChange={(e) => setDescription(e.target.value)}\r\n placeholder=\"Brief description of your research topic...\"\r\n rows={2}\r\n className=\"w-full px-3 py-2 bg-background border rounded-lg focus:outline-none focus:ring-2 focus:ring-ring resize-none transition-all\"\r\n />\r\n </div>\r\n\r\n {/* Drag & Drop File Upload */}\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">\r\n Research Papers <span className=\"text-destructive\">*</span>\r\n </label>\r\n <div\r\n className={cn(\r\n \"relative border-2 border-dashed rounded-xl p-8 text-center transition-all duration-200 ease-in-out\",\r\n dragActive\r\n ? \"border-primary bg-primary/5 scale-[1.01]\"\r\n : \"border-muted-foreground/25 hover:border-primary/50 hover:bg-muted/20\"\r\n )}\r\n onDragEnter={handleDrag}\r\n onDragLeave={handleDrag}\r\n onDragOver={handleDrag}\r\n onDrop={handleDrop}\r\n onClick={() => fileInputRef.current?.click()}\r\n >\r\n <input\r\n ref={fileInputRef}\r\n type=\"file\"\r\n multiple\r\n accept=\".pdf,.doc,.docx\"\r\n onChange={handleFileChange}\r\n className=\"hidden\"\r\n />\r\n\r\n <div className=\"flex flex-col items-center gap-2 pointer-events-none\">\r\n <div className=\"p-3 bg-background rounded-full shadow-sm border\">\r\n <Upload className=\"w-6 h-6 text-primary\" />\r\n </div>\r\n <div>\r\n <p className=\"font-medium\">Click to upload or drag and drop</p>\r\n <p className=\"text-xs text-muted-foreground mt-1\">\r\n PDF or DOCX (max 10MB each)\r\n </p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* File List */}\r\n {files.length > 0 && (\r\n <div className=\"grid grid-cols-1 gap-2 mt-3 max-h-[150px] overflow-y-auto pr-2 custom-scrollbar\">\r\n {files.map((file, index) => (\r\n <div key={index} className=\"flex items-center gap-3 p-2 bg-card border rounded-lg group animate-slideIn\">\r\n <div className=\"p-2 bg-primary/10 rounded\">\r\n <FileType className=\"w-4 h-4 text-primary\" />\r\n </div>\r\n <div className=\"flex-1 min-w-0\">\r\n <p className=\"text-sm font-medium truncate\">{file.name}</p>\r\n <p className=\"text-xs text-muted-foreground\">{(file.size / 1024).toFixed(1)} KB</p>\r\n </div>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"h-8 w-8 text-muted-foreground hover:text-destructive opacity-0 group-hover:opacity-100 transition-opacity\"\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n removeFile(index);\r\n }}\r\n >\r\n <X className=\"w-4 h-4\" />\r\n </Button>\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n\r\n <DialogFooter className=\"sm:justify-between\">\r\n {!isCreating && (\r\n <>\r\n <Button variant=\"ghost\" onClick={() => onOpenChange(false)}>\r\n Cancel\r\n </Button>\r\n <Button\r\n onClick={handleCreate}\r\n disabled={!projectName.trim() || files.length === 0}\r\n className=\"gap-2\"\r\n >\r\n Create Project\r\n <CheckCircle2 className=\"w-4 h-4\" />\r\n </Button>\r\n </>\r\n )}\r\n </DialogFooter>\r\n </DialogContent>\r\n </Dialog>\r\n );\r\n}\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\outline-editor.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'X' is defined but never used.","line":7,"column":52,"nodeType":null,"messageId":"unusedVar","endLine":7,"endColumn":53},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":22,"column":24,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":22,"endColumn":27,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[630,633],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[630,633],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\r\n\r\nimport React, { useState } from 'react';\r\nimport { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';\r\nimport { Button } from '@/components/ui/button';\r\nimport { Input } from '@/components/ui/input';\r\nimport { GripVertical, Plus, Trash2, Edit2, Check, X } from 'lucide-react';\r\n\r\ninterface OutlineSection {\r\n title: string;\r\n description: string;\r\n subsections?: string[];\r\n order: number;\r\n}\r\n\r\ninterface OutlineEditorProps {\r\n outline: {\r\n title: string;\r\n abstract: string;\r\n sections: OutlineSection[];\r\n };\r\n onSave?: (outline: any) => void;\r\n readOnly?: boolean;\r\n}\r\n\r\nexport const OutlineEditor: React.FC<OutlineEditorProps> = ({\r\n outline: initialOutline,\r\n onSave,\r\n readOnly = false,\r\n}) => {\r\n const [outline, setOutline] = useState(initialOutline);\r\n const [editingSection, setEditingSection] = useState<number | null>(null);\r\n const [draggedItem, setDraggedItem] = useState<number | null>(null);\r\n\r\n const handleDragStart = (index: number) => {\r\n setDraggedItem(index);\r\n };\r\n\r\n const handleDragOver = (e: React.DragEvent, index: number) => {\r\n e.preventDefault();\r\n if (draggedItem === null || draggedItem === index) return;\r\n\r\n const newSections = [...outline.sections];\r\n const draggedSection = newSections[draggedItem];\r\n newSections.splice(draggedItem, 1);\r\n newSections.splice(index, 0, draggedSection);\r\n\r\n // Update order\r\n newSections.forEach((section, idx) => {\r\n section.order = idx + 1;\r\n });\r\n\r\n setOutline({ ...outline, sections: newSections });\r\n setDraggedItem(index);\r\n };\r\n\r\n const handleDragEnd = () => {\r\n setDraggedItem(null);\r\n };\r\n\r\n const handleEditSection = (index: number) => {\r\n setEditingSection(index);\r\n };\r\n\r\n const handleSaveSection = (index: number, updates: Partial<OutlineSection>) => {\r\n const newSections = [...outline.sections];\r\n newSections[index] = { ...newSections[index], ...updates };\r\n setOutline({ ...outline, sections: newSections });\r\n setEditingSection(null);\r\n };\r\n\r\n const handleDeleteSection = (index: number) => {\r\n const newSections = outline.sections.filter((_, idx) => idx !== index);\r\n newSections.forEach((section, idx) => {\r\n section.order = idx + 1;\r\n });\r\n setOutline({ ...outline, sections: newSections });\r\n };\r\n\r\n const handleAddSection = () => {\r\n const newSection: OutlineSection = {\r\n title: 'New Section',\r\n description: 'Section description',\r\n subsections: [],\r\n order: outline.sections.length + 1,\r\n };\r\n setOutline({ ...outline, sections: [...outline.sections, newSection] });\r\n setEditingSection(outline.sections.length);\r\n };\r\n\r\n return (\r\n <Card className=\"animate-fadeIn\">\r\n <CardHeader>\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <CardTitle>Research Paper Outline</CardTitle>\r\n <CardDescription>\r\n {readOnly ? 'View paper structure' : 'Drag to reorder, click to edit'}\r\n </CardDescription>\r\n </div>\r\n {!readOnly && (\r\n <div className=\"flex gap-2\">\r\n <Button variant=\"outline\" size=\"sm\" onClick={handleAddSection}>\r\n <Plus className=\"w-4 h-4 mr-2\" />\r\n Add Section\r\n </Button>\r\n {onSave && (\r\n <Button size=\"sm\" onClick={() => onSave(outline)}>\r\n <Check className=\"w-4 h-4 mr-2\" />\r\n Save Changes\r\n </Button>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n </CardHeader>\r\n <CardContent className=\"space-y-4\">\r\n {/* Title */}\r\n <div>\r\n <label className=\"text-sm font-semibold mb-1 block\">Title</label>\r\n <Input\r\n value={outline.title}\r\n onChange={(e) => setOutline({ ...outline, title: e.target.value })}\r\n readOnly={readOnly}\r\n className=\"text-lg font-semibold\"\r\n />\r\n </div>\r\n\r\n {/* Abstract */}\r\n <div>\r\n <label className=\"text-sm font-semibold mb-1 block\">Abstract Outline</label>\r\n <textarea\r\n value={outline.abstract}\r\n onChange={(e) => setOutline({ ...outline, abstract: e.target.value })}\r\n readOnly={readOnly}\r\n className=\"w-full px-3 py-2 bg-background border rounded-lg text-sm min-h-[80px]\"\r\n />\r\n </div>\r\n\r\n {/* Sections */}\r\n <div>\r\n <label className=\"text-sm font-semibold mb-2 block\">Sections</label>\r\n <div className=\"space-y-2\">\r\n {outline.sections.map((section, index) => (\r\n <div\r\n key={index}\r\n draggable={!readOnly}\r\n onDragStart={() => handleDragStart(index)}\r\n onDragOver={(e) => handleDragOver(e, index)}\r\n onDragEnd={handleDragEnd}\r\n className={`border rounded-lg p-4 bg-card ${!readOnly ? 'cursor-move hover:border-primary' : ''\r\n } ${draggedItem === index ? 'opacity-50' : ''}`}\r\n >\r\n <div className=\"flex items-start gap-3\">\r\n {!readOnly && <GripVertical className=\"w-5 h-5 text-muted-foreground mt-1\" />}\r\n\r\n <div className=\"flex-1\">\r\n {editingSection === index ? (\r\n <div className=\"space-y-2\">\r\n <Input\r\n value={section.title}\r\n onChange={(e) =>\r\n handleSaveSection(index, { title: e.target.value })\r\n }\r\n className=\"font-semibold\"\r\n autoFocus\r\n />\r\n <textarea\r\n value={section.description}\r\n onChange={(e) =>\r\n handleSaveSection(index, { description: e.target.value })\r\n }\r\n className=\"w-full px-3 py-2 bg-background border rounded-lg text-sm\"\r\n rows={2}\r\n />\r\n <div className=\"flex gap-2\">\r\n <Button\r\n size=\"sm\"\r\n variant=\"outline\"\r\n onClick={() => setEditingSection(null)}\r\n >\r\n <Check className=\"w-4 h-4\" />\r\n </Button>\r\n </div>\r\n </div>\r\n ) : (\r\n <>\r\n <div className=\"flex items-center justify-between mb-1\">\r\n <h4 className=\"font-semibold\">\r\n {section.order}. {section.title}\r\n </h4>\r\n {!readOnly && (\r\n <div className=\"flex gap-1\">\r\n <Button\r\n size=\"sm\"\r\n variant=\"ghost\"\r\n onClick={() => handleEditSection(index)}\r\n >\r\n <Edit2 className=\"w-4 h-4\" />\r\n </Button>\r\n <Button\r\n size=\"sm\"\r\n variant=\"ghost\"\r\n onClick={() => handleDeleteSection(index)}\r\n >\r\n <Trash2 className=\"w-4 h-4\" />\r\n </Button>\r\n </div>\r\n )}\r\n </div>\r\n <p className=\"text-sm text-muted-foreground\">\r\n {section.description}\r\n </p>\r\n {section.subsections && section.subsections.length > 0 && (\r\n <ul className=\"mt-2 ml-4 text-sm text-muted-foreground list-disc\">\r\n {section.subsections.map((sub, subIdx) => (\r\n <li key={subIdx}>{sub}</li>\r\n ))}\r\n </ul>\r\n )}\r\n </>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n </CardContent>\r\n </Card>\r\n );\r\n};\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\paper-viewer.tsx","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":52,"column":37,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":52,"endColumn":40,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1853,1856],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1853,1856],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\r\n\r\nimport React from 'react';\r\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';\r\nimport { MathRenderer } from './math-renderer';\r\nimport { Button } from './ui/button';\r\nimport { Download, FileText } from 'lucide-react';\r\n\r\ninterface PaperViewerProps {\r\n paper: {\r\n title: string;\r\n abstract: string;\r\n fullText?: string;\r\n introduction?: string;\r\n literatureReview?: string;\r\n methodology?: string;\r\n results?: string;\r\n discussion?: string;\r\n conclusion?: string;\r\n references?: string[];\r\n };\r\n onDownload?: () => void;\r\n}\r\n\r\nexport const PaperViewer: React.FC<PaperViewerProps> = ({ paper, onDownload }) => {\r\n // Use fullText if available, otherwise compile from sections\r\n const content = paper.fullText || compileFromSections(paper);\r\n\r\n return (\r\n <Card className=\"animate-fadeIn\">\r\n <CardHeader>\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-3\">\r\n <FileText className=\"w-6 h-6 text-primary\" />\r\n <CardTitle className=\"text-2xl\">{paper.title}</CardTitle>\r\n </div>\r\n {onDownload && (\r\n <Button variant=\"outline\" onClick={onDownload}>\r\n <Download className=\"w-4 h-4 mr-2\" />\r\n Download PDF\r\n </Button>\r\n )}\r\n </div>\r\n </CardHeader>\r\n <CardContent className=\"prose prose-sm max-w-none dark:prose-invert\">\r\n <MathRenderer content={content} className=\"space-y-6\" />\r\n </CardContent>\r\n </Card>\r\n );\r\n};\r\n\r\nfunction compileFromSections(paper: any): string {\r\n let text = `# ${paper.title}\\n\\n`;\r\n\r\n if (paper.abstract) {\r\n text += `## Abstract\\n\\n${paper.abstract}\\n\\n`;\r\n }\r\n\r\n if (paper.introduction) {\r\n text += `## Introduction\\n\\n${paper.introduction}\\n\\n`;\r\n }\r\n\r\n if (paper.literatureReview) {\r\n text += `## Literature Review\\n\\n${paper.literatureReview}\\n\\n`;\r\n }\r\n\r\n if (paper.methodology) {\r\n text += `## Methodology\\n\\n${paper.methodology}\\n\\n`;\r\n }\r\n\r\n if (paper.results) {\r\n text += `## Results\\n\\n${paper.results}\\n\\n`;\r\n }\r\n\r\n if (paper.discussion) {\r\n text += `## Discussion\\n\\n${paper.discussion}\\n\\n`;\r\n }\r\n\r\n if (paper.conclusion) {\r\n text += `## Conclusion\\n\\n${paper.conclusion}\\n\\n`;\r\n }\r\n\r\n if (paper.references && paper.references.length > 0) {\r\n text += `## References\\n\\n`;\r\n paper.references.forEach((ref: string, idx: number) => {\r\n text += `${idx + 1}. ${ref}\\n`;\r\n });\r\n }\r\n\r\n return text;\r\n}\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\project-card.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'CardDescription' is defined but never used.","line":3,"column":29,"nodeType":null,"messageId":"unusedVar","endLine":3,"endColumn":44},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'Tag' is defined but never used.","line":7,"column":49,"nodeType":null,"messageId":"unusedVar","endLine":7,"endColumn":52},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'getStatusVariant' is assigned a value but never used.","line":16,"column":11,"nodeType":null,"messageId":"unusedVar","endLine":16,"endColumn":27}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\r\n\r\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';\r\nimport { Progress } from '@/components/ui/progress';\r\nimport { Badge } from '@/components/ui/badge';\r\nimport { Project } from '@/lib/types';\r\nimport { FileText, Calendar, TrendingUp, Clock, Tag, MoreHorizontal } from 'lucide-react';\r\nimport { Button } from '@/components/ui/button';\r\n\r\ninterface ProjectCardProps {\r\n project: Project;\r\n onClick?: () => void;\r\n}\r\n\r\nexport function ProjectCard({ project, onClick }: ProjectCardProps) {\r\n const getStatusVariant = (status: Project['status']) => {\r\n switch (status) {\r\n case 'completed':\r\n return 'default';\r\n case 'processing':\r\n return 'secondary';\r\n case 'error':\r\n return 'destructive';\r\n default:\r\n return 'outline';\r\n }\r\n };\r\n\r\n const getStatusText = (status: Project['status']) => {\r\n switch (status) {\r\n case 'completed':\r\n return 'Completed';\r\n case 'processing':\r\n return 'Processing';\r\n case 'error':\r\n return 'Error';\r\n default:\r\n return 'Idle';\r\n }\r\n };\r\n\r\n const getProgressColor = (progress: number) => {\r\n if (progress >= 75) return 'text-primary';\r\n if (progress >= 50) return 'text-chart-3';\r\n return 'text-muted-foreground';\r\n };\r\n\r\n // Mock tags based on project name (in a real app, these would come from the backend)\r\n const tags = ['AI', 'Research', 'Analysis'];\r\n if (project.title.toLowerCase().includes('quantum')) tags.push('Quantum');\r\n if (project.title.toLowerCase().includes('bio')) tags.push('Biology');\r\n if (project.title.toLowerCase().includes('climate')) tags.push('Climate');\r\n\r\n return (\r\n <Card\r\n className=\"group relative overflow-hidden cursor-pointer transition-all duration-300 hover:shadow-premium-lg hover:-translate-y-1 border-muted/40 bg-card/50 backdrop-blur-sm\"\r\n onClick={onClick}\r\n >\r\n {/* Top colored bar to simulate folder tab */}\r\n <div className=\"absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-primary/50 via-secondary/50 to-primary/50 opacity-50 group-hover:opacity-100 transition-opacity\" />\r\n\r\n <CardHeader className=\"pb-3\">\r\n <div className=\"flex items-start justify-between gap-4\">\r\n <div className=\"space-y-1.5\">\r\n <CardTitle className=\"text-xl font-serif leading-tight group-hover:text-primary transition-colors\">\r\n {project.title}\r\n </CardTitle>\r\n <div className=\"flex flex-wrap gap-2\">\r\n {tags.slice(0, 3).map(tag => (\r\n <Badge key={tag} variant=\"secondary\" className=\"text-[10px] h-5 px-1.5 font-normal bg-secondary/50 text-secondary-foreground/80\">\r\n {tag}\r\n </Badge>\r\n ))}\r\n </div>\r\n </div>\r\n <Button variant=\"ghost\" size=\"icon\" className=\"h-8 w-8 -mr-2 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity\">\r\n <MoreHorizontal className=\"w-4 h-4\" />\r\n </Button>\r\n </div>\r\n </CardHeader>\r\n\r\n <CardContent>\r\n <p className=\"text-sm text-muted-foreground line-clamp-2 mb-6 h-10\">\r\n {project.description || 'No description provided.'}\r\n </p>\r\n\r\n <div className=\"space-y-4\">\r\n {/* Progress Section */}\r\n <div className=\"space-y-2\">\r\n <div className=\"flex items-center justify-between text-xs\">\r\n <span className=\"text-muted-foreground flex items-center gap-1.5\">\r\n {project.status === 'processing' ? (\r\n <Clock className=\"w-3 h-3 animate-pulse text-primary\" />\r\n ) : (\r\n <TrendingUp className=\"w-3 h-3\" />\r\n )}\r\n {getStatusText(project.status)}\r\n </span>\r\n <span className={`font-mono font-medium ${getProgressColor(project.progress)}`}>\r\n {project.progress}%\r\n </span>\r\n </div>\r\n <Progress value={project.progress} className=\"h-1.5 bg-muted/50\" />\r\n </div>\r\n\r\n {/* Footer Metadata */}\r\n <div className=\"flex items-center justify-between pt-4 border-t border-border/50\">\r\n <div className=\"flex items-center gap-3 text-xs text-muted-foreground\">\r\n <div className=\"flex items-center gap-1.5\">\r\n <FileText className=\"w-3.5 h-3.5\" />\r\n <span>{project.documentCount}</span>\r\n </div>\r\n <div className=\"flex items-center gap-1.5\">\r\n <Calendar className=\"w-3.5 h-3.5\" />\r\n <span>{project.lastUpdated.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })}</span>\r\n </div>\r\n </div>\r\n\r\n <div className=\"opacity-0 group-hover:opacity-100 transition-opacity transform translate-x-2 group-hover:translate-x-0 duration-300\">\r\n <span className=\"text-xs font-medium text-primary flex items-center gap-1\">\r\n View Details ΓåÆ\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </CardContent>\r\n </Card>\r\n );\r\n}\r\n\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\project-details-view.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'Download' is defined but never used.","line":16,"column":32,"nodeType":null,"messageId":"unusedVar","endLine":16,"endColumn":40},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":25,"column":14,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":25,"endColumn":17,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1149,1152],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1149,1152],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":38,"column":17,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":38,"endColumn":20,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1590,1593],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1590,1593],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\r\n\r\nimport { useState } from 'react';\r\nimport { Button } from '@/components/ui/button';\r\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';\r\nimport { AgentPipeline } from '@/components/agent-pipeline';\r\nimport { QualityMetricsChart } from '@/components/quality-metrics-chart';\r\nimport { CitationChart } from '@/components/citation-chart';\r\nimport { WordCountTrend } from '@/components/word-count-trend';\r\nimport { ConceptNetwork } from '@/components/concept-network';\r\nimport { HypothesisTable } from '@/components/hypothesis-table';\r\nimport { TopicClusterHeatmap } from '@/components/topic-cluster-heatmap';\r\nimport { OutlineEditor } from '@/components/outline-editor';\r\nimport { PaperViewer } from '@/components/paper-viewer';\r\nimport { StatisticsViewer } from '@/components/statistics-viewer';\r\nimport { ArrowLeft, RefreshCw, Download, FileText, Presentation } from 'lucide-react';\r\nimport { generateThemedPPT } from '@/lib/ppt-generator';\r\nimport {\r\n mockQualityMetrics,\r\n mockCitationData,\r\n mockWordCountTrend,\r\n} from '@/lib/mock-data';\r\n\r\ninterface ProjectDetailsViewProps {\r\n project: any;\r\n onBack: () => void;\r\n onRefresh?: () => void;\r\n}\r\n\r\nexport function ProjectDetailsView({ project, onBack, onRefresh }: ProjectDetailsViewProps) {\r\n const [activeTab, setActiveTab] = useState('overview');\r\n\r\n if (!project) return null;\r\n\r\n // Get the latest outline and presentation from agentRuns\r\n const getLatestAgentOutput = (agentName: string) => {\r\n const run = project.agentRuns?.find(\r\n (r: any) => r.agentName === agentName && r.status === 'completed' && r.output\r\n );\r\n return run ? JSON.parse(run.output) : null;\r\n };\r\n\r\n const outline = getLatestAgentOutput('outliner');\r\n const paper = getLatestAgentOutput('writer');\r\n const presentation = getLatestAgentOutput('presenter');\r\n\r\n const handleDownloadPPT = async () => {\r\n if (presentation && presentation.slides) {\r\n generateThemedPPT(presentation.slides, `${project.name}_Presentation`);\r\n } else {\r\n // Fetch from API if not in agent runs\r\n try {\r\n const response = await fetch(`/api/download/ppt/${project.id}`);\r\n const data = await response.json();\r\n if (data.slides) {\r\n generateThemedPPT(data.slides, data.title || `${project.name}_Presentation`);\r\n }\r\n } catch (error) {\r\n console.error('Failed to download PPT:', error);\r\n alert('No presentation available yet. Please wait for the pipeline to complete.');\r\n }\r\n }\r\n };\r\n\r\n return (\r\n <div className=\"space-y-8 animate-fadeIn\">\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-4\">\r\n <Button variant=\"ghost\" size=\"icon\" onClick={onBack} className=\"rounded-full hover:bg-muted\">\r\n <ArrowLeft className=\"w-5 h-5\" />\r\n </Button>\r\n <div>\r\n <h1 className=\"text-3xl font-serif font-bold text-foreground\">\r\n {project.name}\r\n </h1>\r\n <p className=\"text-muted-foreground\">\r\n {project.description || 'Research Project Analysis'}\r\n </p>\r\n </div>\r\n </div>\r\n <div className=\"flex gap-2\">\r\n {presentation && (\r\n <Button variant=\"default\" size=\"sm\" onClick={handleDownloadPPT} className=\"gap-2\">\r\n <Presentation className=\"w-4 h-4\" />\r\n Download PPT\r\n </Button>\r\n )}\r\n <Button variant=\"outline\" size=\"sm\" onClick={onRefresh} className=\"gap-2\">\r\n <RefreshCw className=\"w-4 h-4\" />\r\n Refresh\r\n </Button>\r\n </div>\r\n </div>\r\n\r\n {/* Pipeline Status */}\r\n <section className=\"animate-fadeIn\" style={{ animationDelay: '0.1s' }}>\r\n <h2 className=\"text-2xl font-serif font-semibold mb-6 flex items-center gap-2\">\r\n <span className=\"w-1 h-8 bg-chart-2 rounded-full\" />\r\n Pipeline Status\r\n </h2>\r\n <AgentPipeline\r\n status={project.status}\r\n progress={project.progress}\r\n agentRuns={project.agentRuns}\r\n />\r\n </section>\r\n\r\n {/* Tabs for different views */}\r\n <Tabs value={activeTab} onValueChange={setActiveTab} className=\"w-full\">\r\n <TabsList className=\"grid w-full grid-cols-4\">\r\n <TabsTrigger value=\"overview\">Overview</TabsTrigger>\r\n <TabsTrigger value=\"outline\">Outline</TabsTrigger>\r\n <TabsTrigger value=\"paper\">Paper</TabsTrigger>\r\n <TabsTrigger value=\"analytics\">Analytics</TabsTrigger>\r\n <TabsTrigger value=\"statistics\">Statistics</TabsTrigger>\r\n </TabsList>\r\n\r\n {/* Overview Tab */}\r\n <TabsContent value=\"overview\" className=\"space-y-8\">\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-8\">\r\n <section>\r\n <h2 className=\"text-2xl font-serif font-semibold mb-6 flex items-center gap-2\">\r\n <span className=\"w-1 h-8 bg-chart-4 rounded-full\" />\r\n Quality Metrics\r\n </h2>\r\n <QualityMetricsChart metrics={mockQualityMetrics} />\r\n </section>\r\n\r\n <section>\r\n <h2 className=\"text-2xl font-serif font-semibold mb-6 flex items-center gap-2\">\r\n <span className=\"w-1 h-8 bg-chart-5 rounded-full\" />\r\n Citation Analysis\r\n </h2>\r\n <CitationChart data={mockCitationData} />\r\n </section>\r\n </div>\r\n\r\n <section>\r\n <h2 className=\"text-2xl font-serif font-semibold mb-6 flex items-center gap-2\">\r\n <span className=\"w-1 h-8 bg-chart-1 rounded-full\" />\r\n Word Count Trend\r\n </h2>\r\n <WordCountTrend data={mockWordCountTrend} />\r\n </section>\r\n\r\n <div className=\"grid grid-cols-1 xl:grid-cols-2 gap-8\">\r\n <section>\r\n <h2 className=\"text-2xl font-serif font-semibold mb-6 flex items-center gap-2\">\r\n <span className=\"w-1 h-8 bg-chart-3 rounded-full\" />\r\n Concept Network\r\n </h2>\r\n <ConceptNetwork nodes={project.conceptNodes || []} />\r\n </section>\r\n\r\n <section>\r\n <h2 className=\"text-2xl font-serif font-semibold mb-6 flex items-center gap-2\">\r\n <span className=\"w-1 h-8 bg-chart-2 rounded-full\" />\r\n Generated Hypotheses\r\n </h2>\r\n <HypothesisTable hypotheses={project.hypotheses || []} />\r\n </section>\r\n </div>\r\n </TabsContent>\r\n\r\n {/* Outline Tab */}\r\n <TabsContent value=\"outline\">\r\n {outline ? (\r\n <OutlineEditor outline={outline} readOnly={true} />\r\n ) : (\r\n <div className=\"text-center py-12 text-muted-foreground\">\r\n <FileText className=\"w-16 h-16 mx-auto mb-4 opacity-50\" />\r\n <p>Outline will appear here once the outliner agent completes.</p>\r\n </div>\r\n )}\r\n </TabsContent>\r\n\r\n {/* Paper Tab */}\r\n <TabsContent value=\"paper\">\r\n {paper ? (\r\n <PaperViewer paper={paper} />\r\n ) : (\r\n <div className=\"text-center py-12 text-muted-foreground\">\r\n <FileText className=\"w-16 h-16 mx-auto mb-4 opacity-50\" />\r\n <p>Research paper will appear here once the writer agent completes.</p>\r\n </div>\r\n )}\r\n </TabsContent>\r\n\r\n {/* Analytics Tab */}\r\n <TabsContent value=\"analytics\" className=\"space-y-8\">\r\n <TopicClusterHeatmap />\r\n\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-8\">\r\n <QualityMetricsChart metrics={mockQualityMetrics} />\r\n <CitationChart data={mockCitationData} />\r\n </div>\r\n </TabsContent>\r\n\r\n {/* Statistics Tab */}\r\n <TabsContent value=\"statistics\">\r\n <StatisticsViewer statistics={project.statistics || []} />\r\n </TabsContent>\r\n </Tabs>\r\n </div>\r\n );\r\n}\r\n\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\quality-metrics-chart.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\sidebar.tsx","messages":[{"ruleId":"react-hooks/set-state-in-effect","severity":2,"message":"Error: Calling setState synchronously within an effect can trigger cascading renders\n\nEffects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:\n* Update external systems with the latest state from React.\n* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\nCalling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect).\n\nC:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\sidebar.tsx:20:9\n 18 | // Initialize theme on mount\n 19 | useEffect(() => {\n> 20 | setMounted(true);\n | ^^^^^^^^^^ Avoid calling setState() directly within an effect\n 21 |\n 22 | // Check for saved theme preference or default to system preference\n 23 | const savedTheme = localStorage.getItem('theme');","line":20,"column":9,"nodeType":null,"endLine":20,"endColumn":19}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\r\n\r\nimport { useState, useEffect } from 'react';\r\nimport { Button } from '@/components/ui/button';\r\nimport { Home, FolderOpen, BarChart3, Settings, Plus, Moon, Sun } from 'lucide-react';\r\nimport { cn } from '@/lib/utils';\r\n\r\ninterface SidebarProps {\r\n onNewProject?: () => void;\r\n activeTab?: string;\r\n onTabChange?: (tab: 'dashboard' | 'projects' | 'analytics' | 'settings') => void;\r\n}\r\n\r\nexport function Sidebar({ onNewProject, activeTab = 'dashboard', onTabChange }: SidebarProps) {\r\n const [isDark, setIsDark] = useState(false);\r\n const [mounted, setMounted] = useState(false);\r\n\r\n // Initialize theme on mount\r\n useEffect(() => {\r\n setMounted(true);\r\n\r\n // Check for saved theme preference or default to system preference\r\n const savedTheme = localStorage.getItem('theme');\r\n const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;\r\n\r\n const shouldBeDark = savedTheme === 'dark' || (!savedTheme && prefersDark);\r\n\r\n setIsDark(shouldBeDark);\r\n if (shouldBeDark) {\r\n document.documentElement.classList.add('dark');\r\n } else {\r\n document.documentElement.classList.remove('dark');\r\n }\r\n }, []);\r\n\r\n const toggleTheme = () => {\r\n const newTheme = !isDark;\r\n setIsDark(newTheme);\r\n\r\n if (newTheme) {\r\n document.documentElement.classList.add('dark');\r\n localStorage.setItem('theme', 'dark');\r\n } else {\r\n document.documentElement.classList.remove('dark');\r\n localStorage.setItem('theme', 'light');\r\n }\r\n };\r\n\r\n const menuItems = [\r\n { id: 'dashboard' as const, label: 'Dashboard', icon: Home },\r\n { id: 'projects' as const, label: 'Projects', icon: FolderOpen },\r\n { id: 'analytics' as const, label: 'Analytics', icon: BarChart3 },\r\n { id: 'settings' as const, label: 'Settings', icon: Settings },\r\n ];\r\n\r\n // Prevent hydration mismatch\r\n if (!mounted) {\r\n return (\r\n <div className=\"w-64 h-screen bg-sidebar border-r border-sidebar-border flex flex-col animate-pulse\">\r\n <div className=\"p-6 border-b border-sidebar-border\">\r\n <div className=\"h-8 bg-muted rounded w-32 mb-2\" />\r\n <div className=\"h-4 bg-muted rounded w-24\" />\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"w-64 h-screen bg-sidebar border-r border-sidebar-border flex flex-col animate-slideIn\">\r\n {/* Header */}\r\n <div className=\"p-6 border-b border-sidebar-border\">\r\n <h1 className=\"text-2xl font-serif font-bold text-sidebar-foreground\">\r\n AI Research\r\n </h1>\r\n <p className=\"text-sm text-sidebar-foreground/60 mt-1\">Paper Generator</p>\r\n </div>\r\n\r\n {/* New Project Button */}\r\n <div className=\"p-4\">\r\n <Button\r\n className=\"w-full justify-start gap-2 transition-smooth hover:scale-[1.02]\"\r\n onClick={onNewProject}\r\n >\r\n <Plus className=\"w-4 h-4\" />\r\n New Project\r\n </Button>\r\n </div>\r\n\r\n {/* Navigation */}\r\n <nav className=\"flex-1 px-3 py-2\">\r\n {menuItems.map((item, index) => {\r\n const Icon = item.icon;\r\n return (\r\n <button\r\n key={item.id}\r\n onClick={() => onTabChange?.(item.id)}\r\n className={cn(\r\n \"w-full flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-smooth mb-1 animate-slideIn\",\r\n activeTab === item.id\r\n ? \"bg-sidebar-accent text-sidebar-accent-foreground shadow-sm\"\r\n : \"text-sidebar-foreground hover:bg-sidebar-accent/50 hover:translate-x-1\"\r\n )}\r\n style={{ animationDelay: `${index * 0.05}s` }}\r\n >\r\n <Icon className=\"w-4 h-4\" />\r\n {item.label}\r\n </button>\r\n );\r\n })}\r\n </nav>\r\n\r\n {/* Theme Toggle */}\r\n <div className=\"p-4 border-t border-sidebar-border\">\r\n <Button\r\n variant=\"outline\"\r\n size=\"sm\"\r\n onClick={toggleTheme}\r\n className=\"w-full justify-start gap-2 transition-smooth hover:scale-[1.02]\"\r\n >\r\n {isDark ? (\r\n <>\r\n <Sun className=\"w-4 h-4 animate-scaleIn\" />\r\n Light Mode\r\n </>\r\n ) : (\r\n <>\r\n <Moon className=\"w-4 h-4 animate-scaleIn\" />\r\n Dark Mode\r\n </>\r\n )}\r\n </Button>\r\n\r\n {/* Theme Indicator */}\r\n <div className=\"mt-2 text-xs text-center text-muted-foreground\">\r\n {isDark ? '≡ƒîÖ Scientific Dark' : 'ΓÿÇ∩╕Å Scientific Light'}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\statistics-viewer.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'groupedStats' is assigned a value but never used.","line":36,"column":11,"nodeType":null,"messageId":"unusedVar","endLine":36,"endColumn":23},{"ruleId":"react/no-unescaped-entities","severity":2,"message":"`\"` can be escaped with `"`, `“`, `"`, `”`.","line":123,"column":41,"nodeType":"JSXText","messageId":"unescapedEntityAlts","suggestions":[{"messageId":"replaceWithAlt","data":{"alt":"""},"fix":{"range":[6037,6080],"text":"\r\n ""},"desc":"Replace with `"`."},{"messageId":"replaceWithAlt","data":{"alt":"“"},"fix":{"range":[6037,6080],"text":"\r\n “"},"desc":"Replace with `“`."},{"messageId":"replaceWithAlt","data":{"alt":"""},"fix":{"range":[6037,6080],"text":"\r\n ""},"desc":"Replace with `"`."},{"messageId":"replaceWithAlt","data":{"alt":"”"},"fix":{"range":[6037,6080],"text":"\r\n ”"},"desc":"Replace with `”`."}]},{"ruleId":"react/no-unescaped-entities","severity":2,"message":"`\"` can be escaped with `"`, `“`, `"`, `”`.","line":123,"column":56,"nodeType":"JSXText","messageId":"unescapedEntityAlts","suggestions":[{"messageId":"replaceWithAlt","data":{"alt":"""},"fix":{"range":[6094,6133],"text":""\r\n "},"desc":"Replace with `"`."},{"messageId":"replaceWithAlt","data":{"alt":"“"},"fix":{"range":[6094,6133],"text":"“\r\n "},"desc":"Replace with `“`."},{"messageId":"replaceWithAlt","data":{"alt":"""},"fix":{"range":[6094,6133],"text":""\r\n "},"desc":"Replace with `"`."},{"messageId":"replaceWithAlt","data":{"alt":"”"},"fix":{"range":[6094,6133],"text":"”\r\n "},"desc":"Replace with `”`."}]}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\r\n\r\nimport React from 'react';\r\nimport { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';\r\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';\r\nimport { Badge } from '@/components/ui/badge';\r\nimport { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Cell } from 'recharts';\r\n\r\ninterface Statistic {\r\n id: string;\r\n category: string;\r\n label: string;\r\n value: number;\r\n unit?: string | null;\r\n context: string;\r\n}\r\n\r\ninterface StatisticsViewerProps {\r\n statistics: Statistic[];\r\n}\r\n\r\nconst COLORS = ['#0088FE', '#00C49F', '#FFBB28', '#FF8042', '#8884d8', '#82ca9d'];\r\n\r\nexport function StatisticsViewer({ statistics }: StatisticsViewerProps) {\r\n if (!statistics || statistics.length === 0) {\r\n return (\r\n <Card>\r\n <CardContent className=\"pt-6 text-center text-muted-foreground\">\r\n No statistical data extracted yet. Run the pipeline to analyze documents.\r\n </CardContent>\r\n </Card>\r\n );\r\n }\r\n\r\n // Group by category\r\n const groupedStats = statistics.reduce((acc, stat) => {\r\n if (!acc[stat.category]) {\r\n acc[stat.category] = [];\r\n }\r\n acc[stat.category].push(stat);\r\n return acc;\r\n }, {} as Record<string, Statistic[]>);\r\n\r\n // Prepare chart data - filter for items that look comparable (e.g. percentages)\r\n const percentageStats = statistics.filter(s => s.unit === '%' || s.unit?.toLowerCase().includes('percent'));\r\n const chartData = percentageStats.slice(0, 10).map(s => ({\r\n name: s.label.length > 15 ? s.label.substring(0, 15) + '...' : s.label,\r\n fullLabel: s.label,\r\n value: s.value,\r\n category: s.category\r\n }));\r\n\r\n return (\r\n <div className=\"space-y-6 animate-fadeIn\">\r\n {/* Chart Section - only if we have percentage data */}\r\n {chartData.length > 0 && (\r\n <Card>\r\n <CardHeader>\r\n <CardTitle>Key Metrics Comparison</CardTitle>\r\n <CardDescription>Visualizing percentage-based statistics found in the research</CardDescription>\r\n </CardHeader>\r\n <CardContent>\r\n <div className=\"h-[300px] w-full\">\r\n <ResponsiveContainer width=\"100%\" height=\"100%\">\r\n <BarChart data={chartData} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}>\r\n <CartesianGrid strokeDasharray=\"3 3\" vertical={false} />\r\n <XAxis dataKey=\"name\" />\r\n <YAxis />\r\n <Tooltip\r\n content={({ active, payload }) => {\r\n if (active && payload && payload.length) {\r\n const data = payload[0].payload;\r\n return (\r\n <div className=\"bg-popover border rounded-lg p-3 shadow-lg\">\r\n <p className=\"font-semibold\">{data.fullLabel}</p>\r\n <p className=\"text-sm\">Value: {data.value}%</p>\r\n <p className=\"text-xs text-muted-foreground\">{data.category}</p>\r\n </div>\r\n );\r\n }\r\n return null;\r\n }}\r\n />\r\n <Bar dataKey=\"value\" radius={[4, 4, 0, 0]}>\r\n {chartData.map((entry, index) => (\r\n <Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />\r\n ))}\r\n </Bar>\r\n </BarChart>\r\n </ResponsiveContainer>\r\n </div>\r\n </CardContent>\r\n </Card>\r\n )}\r\n\r\n {/* Detailed Table Section */}\r\n <Card>\r\n <CardHeader>\r\n <CardTitle>Extracted Statistics</CardTitle>\r\n <CardDescription>Detailed list of quantitative findings from the documents</CardDescription>\r\n </CardHeader>\r\n <CardContent>\r\n <Table>\r\n <TableHeader>\r\n <TableRow>\r\n <TableHead>Category</TableHead>\r\n <TableHead>Metric</TableHead>\r\n <TableHead className=\"text-right\">Value</TableHead>\r\n <TableHead>Context</TableHead>\r\n </TableRow>\r\n </TableHeader>\r\n <TableBody>\r\n {statistics.map((stat) => (\r\n <TableRow key={stat.id}>\r\n <TableCell>\r\n <Badge variant=\"outline\">{stat.category}</Badge>\r\n </TableCell>\r\n <TableCell className=\"font-medium\">{stat.label}</TableCell>\r\n <TableCell className=\"text-right font-mono\">\r\n {stat.value} {stat.unit}\r\n </TableCell>\r\n <TableCell className=\"text-muted-foreground text-sm max-w-md truncate\" title={stat.context}>\r\n \"{stat.context}\"\r\n </TableCell>\r\n </TableRow>\r\n ))}\r\n </TableBody>\r\n </Table>\r\n </CardContent>\r\n </Card>\r\n </div>\r\n );\r\n}\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\topic-cluster-heatmap.tsx","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":49,"column":49,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":49,"endColumn":52,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1794,1797],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1794,1797],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"react-hooks/static-components","severity":2,"message":"Error: Cannot create components during render\n\nComponents created during render will reset their state each time they are created. Declare components outside of render.\n\nC:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\topic-cluster-heatmap.tsx:81:48\n 79 | stroke=\"#fff\"\n 80 | >\n> 81 | <Tooltip content={<CustomTooltip />} />\n | ^^^^^^^^^^^^^ This component is created during render\n 82 | </Treemap>\n 83 | </ResponsiveContainer>\n 84 | </div>\n\nC:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\topic-cluster-heatmap.tsx:49:27\n 47 | }));\n 48 |\n> 49 | const CustomTooltip = ({ active, payload }: any) => {\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n> 50 | if (active && payload && payload.length) {\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n> 51 | const data = payload[0].payload;\n ΓǪ\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n> 60 | return null;\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n> 61 | };\n | ^^^^^^ The component is created during render here\n 62 |\n 63 | // Group by category for legend\n 64 | const categories = Array.from(new Set(topics.map(t => t.category)));","line":81,"column":48,"nodeType":null,"endLine":81,"endColumn":61}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use client';\r\n\r\nimport React from 'react';\r\nimport { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';\r\nimport { Treemap, ResponsiveContainer, Tooltip } from 'recharts';\r\n\r\ninterface TopicData {\r\n name: string;\r\n size: number;\r\n category: string;\r\n fill?: string;\r\n}\r\n\r\ninterface TopicClusterHeatmapProps {\r\n topics?: TopicData[];\r\n}\r\n\r\nconst COLORS = {\r\n 'Machine Learning': '#3B82F6',\r\n 'Healthcare': '#10B981',\r\n 'Ethics': '#8B5CF6',\r\n 'Data Science': '#F59E0B',\r\n 'AI Research': '#EF4444',\r\n 'Natural Language Processing': '#06B6D4',\r\n 'Computer Vision': '#EC4899',\r\n 'Other': '#6B7280',\r\n};\r\n\r\nconst defaultTopics: TopicData[] = [\r\n { name: 'Deep Learning Models', size: 25, category: 'Machine Learning' },\r\n { name: 'Neural Networks', size: 20, category: 'Machine Learning' },\r\n { name: 'Medical Imaging', size: 18, category: 'Healthcare' },\r\n { name: 'Clinical Trials', size: 15, category: 'Healthcare' },\r\n { name: 'AI Ethics', size: 12, category: 'Ethics' },\r\n { name: 'Bias Detection', size: 10, category: 'Ethics' },\r\n { name: 'Data Mining', size: 16, category: 'Data Science' },\r\n { name: 'Statistical Analysis', size: 14, category: 'Data Science' },\r\n { name: 'Transformers', size: 22, category: 'Natural Language Processing' },\r\n { name: 'Text Classification', size: 18, category: 'Natural Language Processing' },\r\n];\r\n\r\nexport const TopicClusterHeatmap: React.FC<TopicClusterHeatmapProps> = ({ topics = defaultTopics }) => {\r\n // Add color based on category\r\n const enrichedTopics = topics.map(topic => ({\r\n ...topic,\r\n fill: COLORS[topic.category as keyof typeof COLORS] || COLORS.Other,\r\n }));\r\n\r\n const CustomTooltip = ({ active, payload }: any) => {\r\n if (active && payload && payload.length) {\r\n const data = payload[0].payload;\r\n return (\r\n <div className=\"bg-popover border rounded-lg p-3 shadow-lg\">\r\n <p className=\"font-semibold text-sm\">{data.name}</p>\r\n <p className=\"text-xs text-muted-foreground\">Category: {data.category}</p>\r\n <p className=\"text-xs text-muted-foreground\">Papers: {data.size}</p>\r\n </div>\r\n );\r\n }\r\n return null;\r\n };\r\n\r\n // Group by category for legend\r\n const categories = Array.from(new Set(topics.map(t => t.category)));\r\n\r\n return (\r\n <Card className=\"animate-fadeIn\">\r\n <CardHeader>\r\n <CardTitle>Topic Distribution</CardTitle>\r\n <CardDescription>Research topics clustered by category</CardDescription>\r\n </CardHeader>\r\n <CardContent>\r\n <div className=\"h-[400px]\">\r\n <ResponsiveContainer width=\"100%\" height=\"100%\">\r\n <Treemap\r\n data={enrichedTopics}\r\n dataKey=\"size\"\r\n aspectRatio={4 / 3}\r\n stroke=\"#fff\"\r\n >\r\n <Tooltip content={<CustomTooltip />} />\r\n </Treemap>\r\n </ResponsiveContainer>\r\n </div>\r\n\r\n {/* Legend */}\r\n <div className=\"mt-4 flex flex-wrap gap-3\">\r\n {categories.map(category => (\r\n <div key={category} className=\"flex items-center gap-2\">\r\n <div\r\n className=\"w-4 h-4 rounded\"\r\n style={{ backgroundColor: COLORS[category as keyof typeof COLORS] || COLORS.Other }}\r\n />\r\n <span className=\"text-sm text-muted-foreground\">{category}</span>\r\n </div>\r\n ))}\r\n </div>\r\n </CardContent>\r\n </Card>\r\n );\r\n};\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\ui\\badge.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\ui\\button.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\ui\\card.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\ui\\chart.tsx","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":112,"column":19,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":112,"endColumn":22,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3962,3965],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3962,3965],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":113,"column":17,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":113,"endColumn":20,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3983,3986],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3983,3986],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":188,"column":41,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":188,"endColumn":44,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[6182,6185],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[6182,6185],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":188,"column":53,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":188,"endColumn":56,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[6194,6197],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[6194,6197],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":267,"column":19,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":267,"endColumn":22,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[10741,10744],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[10741,10744],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":289,"column":37,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":289,"endColumn":40,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[11311,11314],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[11311,11314],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":6,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\"use client\"\r\n\r\nimport * as React from \"react\"\r\nimport * as RechartsPrimitive from \"recharts\"\r\n\r\nimport { cn } from \"@/lib/utils\"\r\n\r\n// Format: { THEME_NAME: CSS_SELECTOR }\r\nconst THEMES = { light: \"\", dark: \".dark\" } as const\r\n\r\nexport type ChartConfig = {\r\n [k in string]: {\r\n label?: React.ReactNode\r\n icon?: React.ComponentType\r\n } & (\r\n | { color?: string; theme?: never }\r\n | { color?: never; theme: Record<keyof typeof THEMES, string> }\r\n )\r\n}\r\n\r\ntype ChartContextProps = {\r\n config: ChartConfig\r\n}\r\n\r\nconst ChartContext = React.createContext<ChartContextProps | null>(null)\r\n\r\nfunction useChart() {\r\n const context = React.useContext(ChartContext)\r\n\r\n if (!context) {\r\n throw new Error(\"useChart must be used within a <ChartContainer />\")\r\n }\r\n\r\n return context\r\n}\r\n\r\nconst ChartContainer = React.forwardRef<\r\n HTMLDivElement,\r\n React.ComponentProps<\"div\"> & {\r\n config: ChartConfig\r\n children: React.ComponentProps<typeof RechartsPrimitive.ResponsiveContainer>[\"children\"]\r\n }\r\n>(({ id, className, children, config, ...props }, ref) => {\r\n const uniqueId = React.useId()\r\n const chartId = `chart-${id || uniqueId.replace(/:/g, \"\")}`\r\n\r\n return (\r\n <ChartContext.Provider value={{ config }}>\r\n <div\r\n data-chart={chartId}\r\n ref={ref}\r\n className={cn(\r\n \"flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n <ChartStyle id={chartId} config={config} />\r\n <RechartsPrimitive.ResponsiveContainer>\r\n {children}\r\n </RechartsPrimitive.ResponsiveContainer>\r\n </div>\r\n </ChartContext.Provider>\r\n )\r\n})\r\nChartContainer.displayName = \"ChartContainer\"\r\n\r\nconst ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {\r\n const colorConfig = Object.entries(config).filter(\r\n ([, config]) => config.theme || config.color\r\n )\r\n\r\n if (!colorConfig.length) {\r\n return null\r\n }\r\n\r\n return (\r\n <style\r\n dangerouslySetInnerHTML={{\r\n __html: Object.entries(THEMES)\r\n .map(\r\n ([theme, prefix]) => `\r\n${prefix} [data-chart=${id}] {\r\n${colorConfig\r\n .map(([key, itemConfig]) => {\r\n const color =\r\n itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||\r\n itemConfig.color\r\n return color ? ` --color-${key}: ${color};` : null\r\n })\r\n .join(\"\\n\")}\r\n}\r\n`\r\n )\r\n .join(\"\\n\"),\r\n }}\r\n />\r\n )\r\n}\r\n\r\nconst ChartTooltip = RechartsPrimitive.Tooltip\r\n\r\nconst ChartTooltipContent = React.forwardRef<\r\n HTMLDivElement,\r\n React.ComponentProps<typeof RechartsPrimitive.Tooltip> &\r\n React.ComponentProps<\"div\"> & {\r\n hideLabel?: boolean\r\n hideIndicator?: boolean\r\n indicator?: \"line\" | \"dot\" | \"dashed\"\r\n nameKey?: string\r\n labelKey?: string\r\n payload?: any\r\n label?: any\r\n }\r\n>(\r\n (\r\n {\r\n active,\r\n payload,\r\n className,\r\n indicator = \"dot\",\r\n hideLabel = false,\r\n hideIndicator = false,\r\n label,\r\n labelFormatter,\r\n labelClassName,\r\n formatter,\r\n color,\r\n nameKey,\r\n labelKey,\r\n },\r\n ref\r\n ) => {\r\n const { config } = useChart()\r\n\r\n const tooltipLabel = React.useMemo(() => {\r\n if (hideLabel || !payload?.length) {\r\n return null\r\n }\r\n\r\n const [item] = payload\r\n const key = `${labelKey || item.dataKey || item.name || \"value\"}`\r\n const itemConfig = getPayloadConfigFromPayload(config, item, key)\r\n const value =\r\n !labelKey && typeof label === \"string\"\r\n ? config[label as keyof typeof config]?.label || label\r\n : itemConfig?.label\r\n\r\n if (labelFormatter) {\r\n return (\r\n <div className={cn(\"font-medium\", labelClassName)}>\r\n {labelFormatter(value, payload)}\r\n </div>\r\n )\r\n }\r\n\r\n if (!value) {\r\n return null\r\n }\r\n\r\n return <div className={cn(\"font-medium\", labelClassName)}>{value}</div>\r\n }, [\r\n label,\r\n labelFormatter,\r\n payload,\r\n hideLabel,\r\n labelClassName,\r\n config,\r\n labelKey,\r\n ])\r\n\r\n if (!active || !payload?.length) {\r\n return null\r\n }\r\n\r\n const nestLabel = payload.length === 1 && indicator !== \"dot\"\r\n\r\n return (\r\n <div\r\n ref={ref}\r\n className={cn(\r\n \"grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl\",\r\n className\r\n )}\r\n >\r\n {!nestLabel ? tooltipLabel : null}\r\n <div className=\"grid gap-1.5\">\r\n {payload.map((item: any, index: any) => {\r\n const key = `${nameKey || item.name || item.dataKey || \"value\"}`\r\n const itemConfig = getPayloadConfigFromPayload(config, item, key)\r\n const indicatorColor = color || item.payload.fill || item.color\r\n\r\n return (\r\n <div\r\n key={item.dataKey}\r\n className={cn(\r\n \"flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground\",\r\n indicator === \"dot\" && \"items-center\"\r\n )}\r\n >\r\n {formatter && item?.value !== undefined && item.name ? (\r\n formatter(item.value, item.name, item, index, item.payload)\r\n ) : (\r\n <>\r\n {itemConfig?.icon ? (\r\n <itemConfig.icon />\r\n ) : (\r\n !hideIndicator && (\r\n <div\r\n className={cn(\r\n \"shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]\",\r\n {\r\n \"h-2.5 w-2.5\": indicator === \"dot\",\r\n \"w-1\": indicator === \"line\",\r\n \"w-0 border-[1.5px] border-dashed bg-transparent\":\r\n indicator === \"dashed\",\r\n \"my-0.5\": nestLabel && indicator === \"dashed\",\r\n }\r\n )}\r\n style={\r\n {\r\n \"--color-bg\": indicatorColor,\r\n \"--color-border\": indicatorColor,\r\n } as React.CSSProperties\r\n }\r\n />\r\n )\r\n )}\r\n <div\r\n className={cn(\r\n \"flex flex-1 justify-between leading-none\",\r\n nestLabel ? \"items-end\" : \"items-center\"\r\n )}\r\n >\r\n <div className=\"grid gap-1.5\">\r\n {nestLabel ? tooltipLabel : null}\r\n <span className=\"text-muted-foreground\">\r\n {itemConfig?.label || item.name}\r\n </span>\r\n </div>\r\n {item.value && (\r\n <span className=\"font-mono font-medium tabular-nums text-foreground\">\r\n {item.value.toLocaleString()}\r\n </span>\r\n )}\r\n </div>\r\n </>\r\n )}\r\n </div>\r\n )\r\n })}\r\n </div>\r\n </div>\r\n )\r\n }\r\n)\r\nChartTooltipContent.displayName = \"ChartTooltip\"\r\n\r\nconst ChartLegend = RechartsPrimitive.Legend\r\n\r\nconst ChartLegendContent = React.forwardRef<\r\n HTMLDivElement,\r\n React.ComponentProps<\"div\"> &\r\n Pick<RechartsPrimitive.LegendProps, \"verticalAlign\"> & {\r\n hideIcon?: boolean\r\n nameKey?: string\r\n payload?: any\r\n }\r\n>(\r\n (\r\n { className, hideIcon = false, payload, verticalAlign = \"bottom\", nameKey },\r\n ref\r\n ) => {\r\n const { config } = useChart()\r\n\r\n if (!payload?.length) {\r\n return null\r\n }\r\n\r\n return (\r\n <div\r\n ref={ref}\r\n className={cn(\r\n \"flex items-center justify-center gap-4\",\r\n verticalAlign === \"top\" ? \"pb-3\" : \"pt-3\",\r\n className\r\n )}\r\n >\r\n {payload.map((item: any) => {\r\n const key = `${nameKey || item.dataKey || \"value\"}`\r\n const itemConfig = getPayloadConfigFromPayload(config, item, key)\r\n\r\n return (\r\n <div\r\n key={item.value}\r\n className={cn(\r\n \"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground\"\r\n )}\r\n >\r\n {itemConfig?.icon && !hideIcon ? (\r\n <itemConfig.icon />\r\n ) : (\r\n <div\r\n className=\"h-2 w-2 shrink-0 rounded-[2px]\"\r\n style={{\r\n backgroundColor: item.color,\r\n }}\r\n />\r\n )}\r\n {itemConfig?.label}\r\n </div>\r\n )\r\n })}\r\n </div>\r\n )\r\n }\r\n)\r\nChartLegendContent.displayName = \"ChartLegend\"\r\n\r\n// Helper to extract item config from a payload.\r\nfunction getPayloadConfigFromPayload(\r\n config: ChartConfig,\r\n payload: unknown,\r\n key: string\r\n) {\r\n if (typeof payload !== \"object\" || payload === null) {\r\n return undefined\r\n }\r\n\r\n const payloadPayload =\r\n \"payload\" in payload &&\r\n typeof payload.payload === \"object\" &&\r\n payload.payload !== null\r\n ? payload.payload\r\n : undefined\r\n\r\n let configLabelKey: string = key\r\n\r\n if (\r\n key in payload &&\r\n typeof payload[key as keyof typeof payload] === \"string\"\r\n ) {\r\n configLabelKey = payload[key as keyof typeof payload] as string\r\n } else if (\r\n payloadPayload &&\r\n key in payloadPayload &&\r\n typeof payloadPayload[key as keyof typeof payloadPayload] === \"string\"\r\n ) {\r\n configLabelKey = payloadPayload[\r\n key as keyof typeof payloadPayload\r\n ] as string\r\n }\r\n\r\n return configLabelKey in config\r\n ? config[configLabelKey]\r\n : config[key as keyof typeof config]\r\n}\r\n\r\nexport {\r\n ChartContainer,\r\n ChartTooltip,\r\n ChartTooltipContent,\r\n ChartLegend,\r\n ChartLegendContent,\r\n ChartStyle,\r\n}\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\ui\\dialog.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\ui\\input.tsx","messages":[{"ruleId":"@typescript-eslint/no-empty-object-type","severity":2,"message":"An interface declaring no members is equivalent to its supertype.","line":4,"column":18,"nodeType":"Identifier","messageId":"noEmptyInterfaceWithSuper","endLine":4,"endColumn":28,"suggestions":[{"messageId":"replaceEmptyInterfaceWithSuper","fix":{"range":[77,153],"text":"type InputProps = React.InputHTMLAttributes<HTMLInputElement>"},"desc":"Replace empty interface with a type alias."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import * as React from 'react';\r\nimport { cn } from '@/lib/utils';\r\n\r\nexport interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> { }\r\n\r\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\r\n ({ className, type, ...props }, ref) => {\r\n return (\r\n <input\r\n type={type}\r\n className={cn(\r\n 'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',\r\n className\r\n )}\r\n ref={ref}\r\n {...props}\r\n />\r\n );\r\n }\r\n);\r\nInput.displayName = 'Input';\r\n\r\nexport { Input };\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\ui\\progress.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\ui\\table.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\ui\\tabs.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\ui\\toast.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\components\\word-count-trend.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\eslint.config.mjs","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\hooks\\use-analytics.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\hooks\\use-projects.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":11,"column":16,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":11,"endColumn":19,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[252,255],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[252,255],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { useState, useEffect } from 'react';\r\n\r\nexport interface Project {\r\n id: string;\r\n name: string;\r\n description: string | null;\r\n status: string;\r\n progress: number;\r\n createdAt: string;\r\n updatedAt: string;\r\n documents: any[];\r\n _count: {\r\n documents: number;\r\n };\r\n}\r\n\r\nexport function useProjects() {\r\n const [projects, setProjects] = useState<Project[]>([]);\r\n const [loading, setLoading] = useState(true);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const fetchProjects = async () => {\r\n try {\r\n setLoading(true);\r\n const res = await fetch('/api/projects');\r\n if (!res.ok) throw new Error('Failed to fetch projects');\r\n const data = await res.json();\r\n setProjects(data);\r\n setError(null);\r\n } catch (err) {\r\n setError(err instanceof Error ? err.message : 'Unknown error');\r\n } finally {\r\n setLoading(false);\r\n }\r\n };\r\n\r\n useEffect(() => {\r\n fetchProjects();\r\n // Removed polling - will only fetch on mount or manual refetch\r\n }, []);\r\n\r\n return { projects, loading, error, refetch: fetchProjects };\r\n}\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\agents\\experiment-agent.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\agents\\graph-agent.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\agents\\hypothesis-agent.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\agents\\orchestrator.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":211,"column":94,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":211,"endColumn":97,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[8907,8910],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[8907,8910],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { prisma } from '../prisma';\r\nimport { readerAgent } from './reader-agent';\r\nimport { summarizerAgent } from './summarizer-agent';\r\nimport { graphAgent } from './graph-agent';\r\nimport { hypothesisAgent } from './hypothesis-agent';\r\nimport { experimentAgent } from './experiment-agent';\r\nimport { writerAgent } from './writer-agent';\r\nimport { outlinerAgent } from './outliner-agent';\r\nimport { presenterAgent } from './presenter-agent';\r\nimport { reviewerAgent } from './reviewer-agent';\r\nimport { statisticsAgent } from './statistics-agent';\r\n\r\nexport class AgentOrchestrator {\r\n async runPipeline(projectId: string) {\r\n try {\r\n // Update project status\r\n await prisma.project.update({\r\n where: { id: projectId },\r\n data: { status: 'processing', progress: 0 },\r\n });\r\n\r\n // Get all documents for this project\r\n const documents = await prisma.document.findMany({\r\n where: { projectId },\r\n });\r\n\r\n if (documents.length === 0) {\r\n throw new Error('No documents found for project');\r\n }\r\n\r\n // Step 1: Reader Agent\r\n await this.updateProgress(projectId, 10, 'reader', 'running');\r\n const readerOutputs = [];\r\n for (const doc of documents) {\r\n if (doc.extractedText) {\r\n const output = await readerAgent.process(doc.extractedText);\r\n readerOutputs.push(output);\r\n }\r\n }\r\n await this.saveAgentRun(projectId, 'reader', 'completed', readerOutputs);\r\n await this.updateProgress(projectId, 20);\r\n\r\n // Step 2: Summarizer Agent\r\n await this.updateProgress(projectId, 30, 'summarizer', 'running');\r\n const summaries = [];\r\n for (const output of readerOutputs) {\r\n const summary = await summarizerAgent.process(output);\r\n summaries.push(summary);\r\n }\r\n await this.saveAgentRun(projectId, 'summarizer', 'completed', summaries);\r\n await this.updateProgress(projectId, 40);\r\n\r\n // Step 3: Graph Agent\r\n await this.updateProgress(projectId, 50, 'graph', 'running');\r\n const graph = await graphAgent.process(summaries);\r\n await this.saveAgentRun(projectId, 'graph', 'completed', graph);\r\n\r\n // Save concept nodes to database\r\n for (const node of graph.nodes) {\r\n await prisma.conceptNode.create({\r\n data: {\r\n projectId,\r\n label: node.label,\r\n importance: node.importance,\r\n cluster: node.cluster,\r\n },\r\n });\r\n }\r\n await this.updateProgress(projectId, 60);\r\n\r\n // Step 4: Hypothesis Agent\r\n await this.updateProgress(projectId, 70, 'hypothesis', 'running');\r\n const hypotheses = await hypothesisAgent.process(graph);\r\n await this.saveAgentRun(projectId, 'hypothesis', 'completed', hypotheses);\r\n\r\n // Save hypotheses to database\r\n for (const hyp of hypotheses) {\r\n await prisma.hypothesis.create({\r\n data: {\r\n projectId,\r\n title: hyp.title,\r\n description: hyp.description,\r\n testability: hyp.testability,\r\n novelty: hyp.novelty,\r\n feasibility: hyp.feasibility,\r\n category: hyp.category,\r\n },\r\n });\r\n }\r\n await this.updateProgress(projectId, 80);\r\n\r\n // Step 4.5: Outliner Agent\r\n await this.updateProgress(projectId, 82, 'outliner', 'running');\r\n const outline = await outlinerAgent.process(summaries);\r\n await this.saveAgentRun(projectId, 'outliner', 'completed', outline);\r\n\r\n // Save outline to database\r\n await prisma.outline.create({\r\n data: {\r\n projectId,\r\n title: outline.title,\r\n abstract: outline.abstract,\r\n sections: JSON.stringify(outline.sections),\r\n },\r\n });\r\n await this.updateProgress(projectId, 85);\r\n\r\n // Step 4.8: Statistics Agent (NEW)\r\n await this.updateProgress(projectId, 86, 'statistics', 'running');\r\n // Combine summaries to give context for statistics extraction\r\n // Ideally we would use the full text, but summaries might be enough for high-level stats\r\n // Or we can use the readerOutputs which contain more text. \r\n // Let's use readerOutputs sections joined together for better context.\r\n const fullTextForStats = readerOutputs.map(r =>\r\n Object.values(r.sections).join('\\n')\r\n ).join('\\n\\n');\r\n\r\n const statistics = await statisticsAgent.process(fullTextForStats);\r\n await this.saveAgentRun(projectId, 'statistics', 'completed', statistics);\r\n\r\n // Save statistics to database\r\n if (statistics && Array.isArray(statistics)) {\r\n for (const stat of statistics) {\r\n await prisma.statistic.create({\r\n data: {\r\n projectId,\r\n category: stat.category,\r\n label: stat.label,\r\n value: Number(stat.value),\r\n unit: stat.unit,\r\n context: stat.context\r\n }\r\n });\r\n }\r\n }\r\n await this.updateProgress(projectId, 87);\r\n\r\n // Step 5: Experiment Agent\r\n await this.updateProgress(projectId, 88, 'experiment', 'running');\r\n const experiments = await experimentAgent.process(hypotheses);\r\n await this.saveAgentRun(projectId, 'experiment', 'completed', experiments);\r\n await this.updateProgress(projectId, 90);\r\n\r\n // Step 6: Writer Agent (Enhanced with outline)\r\n await this.updateProgress(projectId, 92, 'writer', 'running');\r\n const paper = await writerAgent.processWithOutline(\r\n outline,\r\n summaries,\r\n hypotheses,\r\n experiments\r\n );\r\n await this.saveAgentRun(projectId, 'writer', 'completed', paper);\r\n await this.updateProgress(projectId, 95);\r\n\r\n // Step 7: Reviewer Agent\r\n await this.updateProgress(projectId, 96, 'reviewer', 'running');\r\n const review = await reviewerAgent.process(paper.fullText || '', outline);\r\n await this.saveAgentRun(projectId, 'reviewer', 'completed', review);\r\n await this.updateProgress(projectId, 97);\r\n\r\n // Step 8: Presenter Agent\r\n await this.updateProgress(projectId, 98, 'presenter', 'running');\r\n const presentation = await presenterAgent.process(paper.fullText || '');\r\n await this.saveAgentRun(projectId, 'presenter', 'completed', presentation);\r\n\r\n // Save presentation to database\r\n await prisma.presentation.create({\r\n data: {\r\n projectId,\r\n title: presentation.title,\r\n slides: JSON.stringify(presentation.slides),\r\n },\r\n });\r\n await this.updateProgress(projectId, 100);\r\n\r\n // Mark project as completed\r\n await prisma.project.update({\r\n where: { id: projectId },\r\n data: { status: 'completed', progress: 100 },\r\n });\r\n\r\n return { success: true, paper };\r\n } catch (error) {\r\n console.error('Pipeline Error:', error);\r\n await prisma.project.update({\r\n where: { id: projectId },\r\n data: { status: 'error' },\r\n });\r\n throw error;\r\n }\r\n }\r\n\r\n private async updateProgress(projectId: string, progress: number, agentName?: string, status?: string) {\r\n await prisma.project.update({\r\n where: { id: projectId },\r\n data: { progress },\r\n });\r\n\r\n if (agentName && status) {\r\n await prisma.agentRun.create({\r\n data: {\r\n projectId,\r\n agentName,\r\n status,\r\n startedAt: new Date(),\r\n },\r\n });\r\n }\r\n }\r\n\r\n private async saveAgentRun(projectId: string, agentName: string, status: string, output: any) {\r\n const run = await prisma.agentRun.findFirst({\r\n where: { projectId, agentName, status: 'running' },\r\n orderBy: { createdAt: 'desc' },\r\n });\r\n\r\n if (run) {\r\n await prisma.agentRun.update({\r\n where: { id: run.id },\r\n data: {\r\n status,\r\n output: JSON.stringify(output),\r\n completedAt: new Date(),\r\n },\r\n });\r\n }\r\n }\r\n}\r\n\r\nexport const orchestrator = new AgentOrchestrator();\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\agents\\outliner-agent.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":17,"column":30,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":17,"endColumn":33,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[363,366],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[363,366],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { geminiClient } from '../gemini-client';\r\n\r\nexport interface OutlineSection {\r\n title: string;\r\n description: string;\r\n subsections?: string[];\r\n order: number;\r\n}\r\n\r\nexport interface ResearchOutline {\r\n title: string;\r\n abstract: string;\r\n sections: OutlineSection[];\r\n}\r\n\r\nexport class OutlinerAgent {\r\n async process(summaries: any[]): Promise<ResearchOutline> {\r\n const summariesText = summaries\r\n .map((s, i) => `Document ${i + 1}: ${JSON.stringify(s)}`)\r\n .join('\\n\\n');\r\n\r\n const prompt = `Based on these research document summaries, create a comprehensive research paper outline:\r\n\r\n${summariesText}\r\n\r\nGenerate a structured outline for an academic research paper. Include:\r\n1. A compelling title\r\n2. An abstract outline (key points to cover)\r\n3. Main sections (Introduction, Literature Review, Methodology, Results, Discussion, Conclusion)\r\n4. Subsections for each main section\r\n\r\nReturn as JSON:\r\n{\r\n \"title\": \"Research Paper Title\",\r\n \"abstract\": \"Brief description of what the abstract should cover\",\r\n \"sections\": [\r\n {\r\n \"title\": \"Introduction\",\r\n \"description\": \"What this section should cover\",\r\n \"subsections\": [\"Background\", \"Research Questions\", \"Significance\"],\r\n \"order\": 1\r\n },\r\n {\r\n \"title\": \"Literature Review\",\r\n \"description\": \"Survey of existing research\",\r\n \"subsections\": [\"Historical Context\", \"Current State\", \"Gaps in Research\"],\r\n \"order\": 2\r\n }\r\n ]\r\n}\r\n\r\nIMPORTANT: Include proper academic structure with Introduction, Literature Review, Methodology, Results, Discussion, and Conclusion sections.`;\r\n\r\n try {\r\n const result = await geminiClient.generateJSON<ResearchOutline>(prompt);\r\n return result;\r\n } catch (error) {\r\n console.error('Outliner Agent Error:', error);\r\n // Return default outline\r\n return {\r\n title: 'Research Paper',\r\n abstract: 'This paper explores the key findings from the analyzed documents.',\r\n sections: [\r\n {\r\n title: 'Introduction',\r\n description: 'Introduction to the research topic',\r\n subsections: ['Background', 'Research Questions'],\r\n order: 1,\r\n },\r\n {\r\n title: 'Literature Review',\r\n description: 'Review of existing research',\r\n subsections: ['Key Studies', 'Research Gaps'],\r\n order: 2,\r\n },\r\n {\r\n title: 'Methodology',\r\n description: 'Research methods and approach',\r\n subsections: ['Data Collection', 'Analysis Methods'],\r\n order: 3,\r\n },\r\n {\r\n title: 'Results',\r\n description: 'Key findings',\r\n subsections: ['Primary Findings', 'Secondary Findings'],\r\n order: 4,\r\n },\r\n {\r\n title: 'Discussion',\r\n description: 'Interpretation of results',\r\n subsections: ['Implications', 'Limitations'],\r\n order: 5,\r\n },\r\n {\r\n title: 'Conclusion',\r\n description: 'Summary and future work',\r\n subsections: ['Summary', 'Future Research'],\r\n order: 6,\r\n },\r\n ],\r\n };\r\n }\r\n }\r\n}\r\n\r\nexport const outlinerAgent = new OutlinerAgent();\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\agents\\presenter-agent.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\agents\\reader-agent.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\agents\\reviewer-agent.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":20,"column":51,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":20,"endColumn":54,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[493,496],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[493,496],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { geminiClient } from '../gemini-client';\r\n\r\nexport interface ReviewFeedback {\r\n section: string;\r\n score: number; // 0-100\r\n strengths: string[];\r\n weaknesses: string[];\r\n suggestions: string[];\r\n}\r\n\r\nexport interface ReviewReport {\r\n overallScore: number;\r\n summary: string;\r\n sectionReviews: ReviewFeedback[];\r\n criticalIssues: string[];\r\n recommendations: string[];\r\n}\r\n\r\nexport class ReviewerAgent {\r\n async process(paperContent: string, outline?: any): Promise<ReviewReport> {\r\n const prompt = `You are an academic reviewer evaluating this research paper draft:\r\n\r\n${paperContent.substring(0, 10000)}\r\n\r\n${outline ? `Expected outline structure:\\n${JSON.stringify(outline, null, 2)}\\n` : ''}\r\n\r\nProvide a comprehensive review evaluating:\r\n1. Logical flow and coherence\r\n2. Completeness of each section\r\n3. Quality of arguments and evidence\r\n4. Writing clarity and style\r\n5. Adherence to academic standards\r\n\r\nReturn as JSON:\r\n{\r\n \"overallScore\": 75,\r\n \"summary\": \"Overall assessment in 2-3 sentences\",\r\n \"sectionReviews\": [\r\n {\r\n \"section\": \"Introduction\",\r\n \"score\": 80,\r\n \"strengths\": [\"Clear problem statement\", \"Well-motivated research\"],\r\n \"weaknesses\": [\"Missing some background context\"],\r\n \"suggestions\": [\"Add more literature context\", \"Clarify research gap\"]\r\n }\r\n ],\r\n \"criticalIssues\": [\r\n \"Methodology section needs more detail\",\r\n \"Results lack statistical significance tests\"\r\n ],\r\n \"recommendations\": [\r\n \"Expand the literature review\",\r\n \"Add more quantitative results\",\r\n \"Improve transition between sections\"\r\n ]\r\n}`;\r\n\r\n try {\r\n const result = await geminiClient.generateJSON<ReviewReport>(prompt);\r\n return result;\r\n } catch (error) {\r\n console.error('Reviewer Agent Error:', error);\r\n return {\r\n overallScore: 70,\r\n summary: 'Paper shows promise but needs refinement in several areas.',\r\n sectionReviews: [\r\n {\r\n section: 'Overall',\r\n score: 70,\r\n strengths: ['Coherent structure', 'Clear research direction'],\r\n weaknesses: ['Some sections need more depth'],\r\n suggestions: ['Expand methodology', 'Add more references'],\r\n },\r\n ],\r\n criticalIssues: ['Review unavailable - using default assessment'],\r\n recommendations: [\r\n 'Review each section for completeness',\r\n 'Ensure all claims are supported by evidence',\r\n 'Check for logical flow and transitions',\r\n ],\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Quick validation check for paper completeness\r\n */\r\n async validateCompleteness(paperContent: string, requiredSections: string[]): Promise<{\r\n complete: boolean;\r\n missingSections: string[];\r\n issues: string[];\r\n }> {\r\n const prompt = `Check if this paper contains all required sections: ${requiredSections.join(', ')}\r\n\r\nPaper content:\r\n${paperContent.substring(0, 5000)}\r\n\r\nReturn JSON:\r\n{\r\n \"complete\": true/false,\r\n \"missingSections\": [\"Section Name\"],\r\n \"issues\": [\"Description of any structural issues\"]\r\n}`;\r\n\r\n try {\r\n const result = await geminiClient.generateJSON<{\r\n complete: boolean;\r\n missingSections: string[];\r\n issues: string[];\r\n }>(prompt);\r\n return result;\r\n } catch (error) {\r\n console.error('Validator Error:', error);\r\n return {\r\n complete: false,\r\n missingSections: [],\r\n issues: ['Validation check failed'],\r\n };\r\n }\r\n }\r\n}\r\n\r\nexport const reviewerAgent = new ReviewerAgent();\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\agents\\statistics-agent.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\agents\\summarizer-agent.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\agents\\writer-agent.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":123,"column":71,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":123,"endColumn":74,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[4577,4580],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[4577,4580],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":149,"column":18,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":149,"endColumn":21,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[5518,5521],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[5518,5521],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":189,"column":47,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":189,"endColumn":50,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[7011,7014],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[7011,7014],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { geminiClient } from '../gemini-client';\r\nimport { Summary } from './summarizer-agent';\r\nimport { Hypothesis } from './hypothesis-agent';\r\nimport { Experiment } from './experiment-agent';\r\nimport { ResearchOutline, OutlineSection } from './outliner-agent';\r\n\r\nexport interface ResearchPaper {\r\n title: string;\r\n abstract: string;\r\n introduction: string;\r\n literatureReview: string;\r\n methodology: string;\r\n results: string;\r\n discussion: string;\r\n conclusion: string;\r\n references: string[];\r\n fullText?: string; // Complete paper in markdown with LaTeX\r\n}\r\n\r\nexport interface ChapterContent {\r\n sectionTitle: string;\r\n content: string;\r\n}\r\n\r\nexport class WriterAgent {\r\n /**\r\n * Legacy single-pass writing (kept for backwards compatibility)\r\n */\r\n async process(\r\n summaries: Summary[],\r\n hypotheses: Hypothesis[],\r\n experiments: Experiment[]\r\n ): Promise<ResearchPaper> {\r\n const context = `\r\nSummaries: ${summaries.map(s => s.overall).join(' ')}\r\nTop Hypotheses: ${hypotheses.slice(0, 3).map(h => `${h.title}: ${h.description}`).join('; ')}\r\nExperiments: ${experiments.slice(0, 2).map(e => e.methodology).join('; ')}\r\n`;\r\n\r\n const prompt = `Write a comprehensive research paper based on this context:\r\n\r\n${context}\r\n\r\nIMPORTANT: Use LaTeX notation for any mathematical formulas:\r\n- Inline math: $formula$\r\n- Block math: $$formula$$\r\n\r\nReturn as JSON:\r\n{\r\n \"title\": \"Research Paper Title\",\r\n \"abstract\": \"150-200 word abstract\",\r\n \"introduction\": \"Introduction section with background and research questions\",\r\n \"literatureReview\": \"Comprehensive literature review\",\r\n \"methodology\": \"Detailed methodology section\",\r\n \"results\": \"Expected or preliminary results\",\r\n \"discussion\": \"Discussion of implications and findings\",\r\n \"conclusion\": \"Conclusion and future work\",\r\n \"references\": [\"Reference 1\", \"Reference 2\"]\r\n}`;\r\n\r\n try {\r\n const result = await geminiClient.generateJSON<ResearchPaper>(prompt);\r\n return result;\r\n } catch (error) {\r\n console.error('Writer Agent Error:', error);\r\n return this.getFallbackPaper();\r\n }\r\n }\r\n\r\n /**\r\n * Enhanced recursive chapter-by-chapter writing\r\n */\r\n async processWithOutline(\r\n outline: ResearchOutline,\r\n summaries: Summary[],\r\n hypotheses: Hypothesis[],\r\n experiments: Experiment[]\r\n ): Promise<ResearchPaper> {\r\n const context = {\r\n summaries: summaries.map(s => s.overall).join('\\n\\n'),\r\n hypotheses: hypotheses.map(h => `${h.title}: ${h.description}`).join('\\n'),\r\n experiments: experiments.map(e => `${e.hypothesis}: ${e.methodology}`).join('\\n'),\r\n };\r\n\r\n // Generate abstract first\r\n const abstract = await this.generateAbstract(outline, context);\r\n\r\n // Generate each chapter recursively\r\n const chapters: ChapterContent[] = [];\r\n let previousChapters = '';\r\n\r\n for (const section of outline.sections.sort((a, b) => a.order - b.order)) {\r\n const chapterContent = await this.generateChapter(\r\n section,\r\n context,\r\n outline,\r\n previousChapters\r\n );\r\n chapters.push(chapterContent);\r\n previousChapters += `\\n\\n## ${chapterContent.sectionTitle}\\n${chapterContent.content}`;\r\n }\r\n\r\n // Generate references\r\n const references = await this.generateReferences(context);\r\n\r\n // Compile full paper\r\n const fullText = this.compilePaper(outline.title, abstract, chapters, references);\r\n\r\n return {\r\n title: outline.title,\r\n abstract,\r\n introduction: chapters.find(c => c.sectionTitle.toLowerCase().includes('introduction'))?.content || '',\r\n literatureReview: chapters.find(c => c.sectionTitle.toLowerCase().includes('literature'))?.content || '',\r\n methodology: chapters.find(c => c.sectionTitle.toLowerCase().includes('methodology'))?.content || '',\r\n results: chapters.find(c => c.sectionTitle.toLowerCase().includes('result'))?.content || '',\r\n discussion: chapters.find(c => c.sectionTitle.toLowerCase().includes('discussion'))?.content || '',\r\n conclusion: chapters.find(c => c.sectionTitle.toLowerCase().includes('conclusion'))?.content || '',\r\n references,\r\n fullText,\r\n };\r\n }\r\n\r\n private async generateAbstract(outline: ResearchOutline, context: any): Promise<string> {\r\n const prompt = `Write a 150-200 word academic abstract for this research paper:\r\n\r\nTitle: ${outline.title}\r\nAbstract should cover: ${outline.abstract}\r\n\r\nResearch context:\r\n${context.summaries.substring(0, 1000)}\r\n\r\nKey hypotheses:\r\n${context.hypotheses.substring(0, 500)}\r\n\r\nWrite a compelling abstract that summarizes the research problem, approach, and expected contributions.\r\nUse LaTeX for any formulas: inline $formula$ or block $$formula$$`;\r\n\r\n try {\r\n const result = await geminiClient.generateText(prompt);\r\n return result;\r\n } catch (error) {\r\n console.error('Abstract generation error:', error);\r\n return 'This paper explores novel approaches in the research domain, leveraging advanced methodologies to address key challenges.';\r\n }\r\n }\r\n\r\n private async generateChapter(\r\n section: OutlineSection,\r\n context: any,\r\n outline: ResearchOutline,\r\n previousChapters: string\r\n ): Promise<ChapterContent> {\r\n const prompt = `Write the \"${section.title}\" section of this research paper:\r\n\r\nPaper Title: ${outline.title}\r\nSection Description: ${section.description}\r\nSubsections to cover: ${section.subsections?.join(', ') || 'N/A'}\r\n\r\nResearch Context:\r\n${context.summaries.substring(0, 2000)}\r\n\r\n${previousChapters ? `Previous sections for context:\\n${previousChapters.substring(0, 1500)}` : ''}\r\n\r\nGuidelines:\r\n- Write 500-800 words for this section\r\n- Use academic writing style\r\n- Include LaTeX notation for formulas: $inline$ or $$block$$\r\n- Reference key findings from the research context\r\n- Ensure logical flow and coherence\r\n- ${section.subsections ? `Cover these subsections: ${section.subsections.join(', ')}` : ''}\r\n\r\nWrite the complete section content (do NOT include the section title in your response, just the content):`;\r\n\r\n try {\r\n const content = await geminiClient.generateText(prompt);\r\n return {\r\n sectionTitle: section.title,\r\n content,\r\n };\r\n } catch (error) {\r\n console.error(`Chapter generation error for ${section.title}:`, error);\r\n return {\r\n sectionTitle: section.title,\r\n content: `Content for ${section.title} section is being generated...`,\r\n };\r\n }\r\n }\r\n\r\n private async generateReferences(context: any): Promise<string[]> {\r\n const prompt = `Based on this research context, suggest 8-10 relevant academic references in proper citation format:\r\n\r\n${context.summaries.substring(0, 1500)}\r\n\r\nFormat each reference in APA style. Return as JSON array of strings.`;\r\n\r\n try {\r\n const refs = await geminiClient.generateJSON<string[]>(prompt);\r\n return refs;\r\n } catch (error) {\r\n console.error('References generation error:', error);\r\n return [\r\n 'Smith, J. (2023). Recent Advances in AI Research. Journal of AI Studies, 15(2), 123-145.',\r\n 'Johnson, A., & Lee, B. (2024). Machine Learning Applications. Academic Press.',\r\n ];\r\n }\r\n }\r\n\r\n private compilePaper(\r\n title: string,\r\n abstract: string,\r\n chapters: ChapterContent[],\r\n references: string[]\r\n ): string {\r\n let paper = `# ${title}\\n\\n`;\r\n paper += `## Abstract\\n\\n${abstract}\\n\\n`;\r\n\r\n for (const chapter of chapters) {\r\n paper += `## ${chapter.sectionTitle}\\n\\n${chapter.content}\\n\\n`;\r\n }\r\n\r\n paper += `## References\\n\\n`;\r\n references.forEach((ref, idx) => {\r\n paper += `${idx + 1}. ${ref}\\n`;\r\n });\r\n\r\n return paper;\r\n }\r\n\r\n private getFallbackPaper(): ResearchPaper {\r\n return {\r\n title: 'Generated Research Paper',\r\n abstract: 'Abstract generation in progress...',\r\n introduction: '',\r\n literatureReview: '',\r\n methodology: '',\r\n results: '',\r\n discussion: '',\r\n conclusion: '',\r\n references: [],\r\n };\r\n }\r\n}\r\n\r\nexport const writerAgent = new WriterAgent();\r\n\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\file-processor.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\gemini-client.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\mock-data.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\ppt-generator.ts","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'secondaryColor' is assigned a value but never used.","line":87,"column":11,"nodeType":null,"messageId":"unusedVar","endLine":87,"endColumn":25}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import PptxGenJS from \"pptxgenjs\";\r\n\r\nexport interface SlideData {\r\n title: string;\r\n bullets: string[];\r\n notes?: string;\r\n}\r\n\r\n/**\r\n * Generate a PowerPoint presentation from structured slide data\r\n * @param slides - Array of slide data objects\r\n * @param filename - Name for the output file (without extension)\r\n */\r\nexport const generateResearchPPT = (slides: SlideData[], filename: string) => {\r\n const pres = new PptxGenJS();\r\n\r\n // Set presentation metadata\r\n pres.author = \"AI Research App\";\r\n pres.company = \"Research Platform\";\r\n pres.subject = \"AI-Generated Research Presentation\";\r\n pres.title = filename;\r\n\r\n slides.forEach((slideContent, index) => {\r\n const slide = pres.addSlide();\r\n\r\n // Add slide number footer\r\n slide.addText(`${index + 1} / ${slides.length}`, {\r\n x: \"90%\",\r\n y: \"95%\",\r\n w: \"10%\",\r\n fontSize: 10,\r\n color: \"999999\",\r\n align: \"right\",\r\n });\r\n\r\n // Add Title\r\n slide.addText(slideContent.title, {\r\n x: 0.5,\r\n y: 0.5,\r\n w: \"90%\",\r\n fontSize: 28,\r\n bold: true,\r\n color: \"363636\",\r\n fontFace: \"Arial\",\r\n });\r\n\r\n // Add Bullets\r\n slide.addText(\r\n slideContent.bullets.map((b) => `ΓÇó ${b}`).join(\"\\n\"),\r\n {\r\n x: 0.5,\r\n y: 1.8,\r\n w: \"90%\",\r\n h: \"60%\",\r\n fontSize: 18,\r\n color: \"606060\",\r\n fontFace: \"Arial\",\r\n valign: \"top\",\r\n }\r\n );\r\n\r\n // Add Speaker Notes\r\n if (slideContent.notes) {\r\n slide.addNotes(slideContent.notes);\r\n }\r\n });\r\n\r\n // Write file (browser download)\r\n pres.writeFile({ fileName: `${filename}.pptx` });\r\n};\r\n\r\n/**\r\n * Generate a presentation with a custom theme\r\n */\r\nexport const generateThemedPPT = (\r\n slides: SlideData[],\r\n filename: string,\r\n theme: {\r\n primaryColor?: string;\r\n secondaryColor?: string;\r\n fontFamily?: string;\r\n } = {}\r\n) => {\r\n const pres = new PptxGenJS();\r\n\r\n const primaryColor = theme.primaryColor || \"1E40AF\";\r\n const secondaryColor = theme.secondaryColor || \"3B82F6\";\r\n const fontFamily = theme.fontFamily || \"Arial\";\r\n\r\n pres.author = \"AI Research App\";\r\n pres.subject = \"AI-Generated Research Presentation\";\r\n pres.title = filename;\r\n\r\n slides.forEach((slideContent, index) => {\r\n const slide = pres.addSlide();\r\n\r\n // Add themed background shape\r\n slide.addShape(pres.ShapeType.rect, {\r\n x: 0,\r\n y: 0,\r\n w: \"100%\",\r\n h: 0.8,\r\n fill: { color: primaryColor },\r\n });\r\n\r\n // Add title with white text on colored background\r\n slide.addText(slideContent.title, {\r\n x: 0.5,\r\n y: 0.2,\r\n w: \"90%\",\r\n fontSize: 28,\r\n bold: true,\r\n color: \"FFFFFF\",\r\n fontFace: fontFamily,\r\n });\r\n\r\n // Add slide number\r\n slide.addText(`${index + 1} / ${slides.length}`, {\r\n x: \"90%\",\r\n y: \"95%\",\r\n w: \"10%\",\r\n fontSize: 10,\r\n color: \"999999\",\r\n align: \"right\",\r\n });\r\n\r\n // Add content bullets\r\n slide.addText(\r\n slideContent.bullets.map((b) => `ΓÇó ${b}`).join(\"\\n\"),\r\n {\r\n x: 0.5,\r\n y: 1.5,\r\n w: \"90%\",\r\n h: \"70%\",\r\n fontSize: 18,\r\n color: \"363636\",\r\n fontFace: fontFamily,\r\n valign: \"top\",\r\n }\r\n );\r\n\r\n // Add speaker notes\r\n if (slideContent.notes) {\r\n slide.addNotes(slideContent.notes);\r\n }\r\n });\r\n\r\n pres.writeFile({ fileName: `${filename}.pptx` });\r\n};\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\prisma.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\types.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\utils-data.ts","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":2,"message":"Unexpected any. Specify a different type.","line":2,"column":44,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":2,"endColumn":47,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[104,107],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[104,107],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"// Helper function to convert API project to display format\r\nexport function convertProject(apiProject: any) {\r\n return {\r\n id: apiProject.id,\r\n title: apiProject.name,\r\n description: apiProject.description || '',\r\n status: apiProject.status as 'idle' | 'processing' | 'completed' | 'error',\r\n lastUpdated: new Date(apiProject.updatedAt),\r\n documentCount: apiProject._count?.documents || 0,\r\n progress: apiProject.progress,\r\n };\r\n}\r\n\r\n// Helper to get status badge variant\r\nexport function getStatusVariant(status: string) {\r\n switch (status) {\r\n case 'completed':\r\n return 'default' as const;\r\n case 'processing':\r\n return 'secondary' as const;\r\n case 'error':\r\n return 'destructive' as const;\r\n default:\r\n return 'outline' as const;\r\n }\r\n}\r\n","usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\lib\\utils.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\next.config.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"C:\\Users\\omkar\\OneDrive\\Documents\\New folder (5)\\ai-research-app\\postcss.config.mjs","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]}]