# Project export: DevQ Studio

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: UC Berkeley AI Hackathon 2025
- Tagline: Intelligent code security analysis for modern development teams or Individuals
- Devpost: https://devpost.com/software/gitbase-studio
- GitHub: https://github.com/thekavishshah/code-sentinel-bot
- Demo: https://www.canva.com/design/DAGrEtCkzr8/2eKnjm6lW4Ij-RYxKUYfng/edit?utm_content=DAGrEtCkzr8&utm_campaign=designshare&utm_medium=link2&utm_source=sharebutton
- Video: https://www.youtube.com/embed/jf0kVNp6Blk?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — gpt-engineer-app[bot] (6 commits), Kavish Shah (4 commits), Vishnu Nandam (2 commits)

## Devpost submission (written by the team)

### Overview

🚀

### Inspiration

Code Sentinel Bot was born out of a pressing need: preventable security breaches caused by overlooked vulnerabilities in pull requests. Developers often lack the time or expertise for deep security reviews. With the rise of AI and increasingly complex cyber threats, we saw an opportunity to democratize security expertise by creating an intelligent assistant that embeds security into everyday development. Our goal is to shift security left — enabling every developer to become a security-conscious developer. 🧠 What It Does Code Sentinel Bot is an AI-powered GitHub repository security analyzer that helps developers identify vulnerabilities before code is merged. 🔍 Core Features 🔗 GitHub Integration: Analyzes public GitHub repositories and pull requests in real-time 🤖 AI-Powered Risk Assessment: Uses Claude AI to assign risk scores (0–100%) per PR 🛠️ Security Detection: Flags issues like SQL injection, insecure auth, and more 💬 RAG Chatbot: A Retrieval-Augmented Generation assistant that answers repo-specific questions 📊 Detailed Reports: Provides recommendations and technical analysis 📁 Analysis History: Saves analyzed repositories for continued monitoring 📈 Modern UI: Responsive dashboard with live updates and intuitive design 🏗️ How We Built It 🖥️ Frontend React 18 + TypeScript – Modern, type-safe, and component-based Vite – For fast dev builds and optimized production shadcn/ui + Tailwind CSS – Beautiful and accessible UI React Query – API caching and efficient state management ⚙️ Backend & AI Integration Express.js Server – Backend proxy for AI and GitHub API Supabase Edge Functions – Serverless GitHub repo analysis Claude 3.5 Sonnet (Anthropic) – Natural language processing and code analysis Octokit GitHub API – Pull request and repo data fetching 🧬 AI & Security Pipeline 🔁 RAG System: Context-aware query responses 📐 Semantic Matching: Cosine similarity for code analysis 🛡️ Security Rule Engine: Detects common vulnerability patterns 📉 Risk Scoring: Multi-factor algorithm for threat estimation ☁️ Deployment Full-Stack Deployment: With secure environment management CORS + API Keys: Secure backend services WebSocket-like Updates: Live stream of analysis results 🧗‍♀️ Challenges We Faced Technical GitHub API Rate Limits: Solved via caching and batching Claude Token Limits: Overcame with chunking strategy Balancing Speed vs Accuracy: Used prompt engineering + parallel processing Integration Cross-Browser Compatibility: Required extensive testing State Management: Complex UI and backend state syncing Robust Error Handling: Built for network failures, invalid repos, etc. Performance Bundle Optimization: Lazy loading and code splitting Memory Management: Efficient handling of large repos 🏆 Accomplishments ✅ Seamless integration of GitHub and AI platforms ⚡ Sub-30-second real-time security analysis 🔐 Smart risk scoring algorithm for PRs 💡 RAG implementation for contextual developer Q&A 🎨 Responsive, intuitive UI for all devices 🌍 Democratizing security for small teams and solo devs 📚 What We Learned 📊 AI Prompt Engineering & Token Management 🧩 Advanced React patterns (hooks, context, performance) 🔒 Secure, scalable API design 👨‍💻 UI/UX matters: User testing and feedback made a huge impact 🚦 Trade-offs: Performance vs features 🧠 Building with security in mind from day one 🤝 Cross-functional collaboration & Agile workflows 🔮 What’s Next 📌 Immediate (0–3 months) 🔐 Private & Enterprise GitHub support ⚙️ Advanced vulnerability detection 👥 Team features & account management 📱 Mobile app for real-time monitoring 🗓️ Medium Term (6–12 months) 🧪 CI/CD integration (GitHub Actions, Jenkins, etc.) 🧷 Support for GitLab, Bitbucket, etc. 📜 Customizable security policies 📈 Predictive security trend analytics 🌍 Long-Term Vision (1–2 years) 🧠 AI Security Advisor – proactive recommendations 🌐 Open Source Vulnerability DB 🧑‍🏫 Integrated Security Education Platform 🔗 Blockchain-based audit trails 🧬 ML pipelines for zero-day detection 🔧 Technical Enhancements (Ongoing) ⚡ Faster access with edge computing & caching 🧠 Multi-model AI integration for specialized tasks 🔗 Blockchain compliance logging 📊 Custom-trained ML models for security pattern recognition Code Sentinel Bot is our commitment to a future where security isn't an afterthought — it's AI-assisted, real-time, and developer-first. Together, we can build a safer internet, one pull request at a time.

## README (from the GitHub repository)

# Code Sentinel Bot

![License](https://img.shields.io/badge/license-MIT-blue.svg)
![Version](https://img.shields.io/badge/version-1.0.0-green.svg)
![Built with Lovable](https://img.shields.io/badge/Built%20with-Lovable-ff69b4)

A modern web application for code analysis and monitoring, built with React and TypeScript.

## 📋 Table of Contents

- [Features](#features)
- [Technologies](#technologies)
- [Getting Started](#getting-started)
- [Deployment](#deployment)
- [Custom Domain](#custom-domain)
- [Project Structure](#project-structure)
- [Contributing](#contributing)
- [License](#license)

## ✨ Features

- Modern, responsive UI built with shadcn-ui components
- Code analysis and monitoring capabilities
- Real-time updates and notifications
- Customizable dashboard views
- Comprehensive reporting tools

## 🛠️ Technologies

This project is built with:

- **[Vite](https://vitejs.dev/)** - Next generation frontend tooling
- **[TypeScript](https://www.typescriptlang.org/)** - Typed JavaScript at any scale
- **[React](https://reactjs.org/)** - A JavaScript library for building user interfaces
- **[shadcn-ui](https://ui.shadcn.com/)** - Beautifully designed components
- **[Tailwind CSS](https://tailwindcss.com/)** - A utility-first CSS framework

## 🚀 Getting Started

### Prerequisites

- Node.js (v16 or later)
- npm or yarn

### Development Setup

There are several ways to set up your development environment:

#### Option 1: Use your preferred IDE

If you want to work locally using your own IDE, you can clone this repo and push changes. Pushed changes will also be reflected in Lovable.

```sh
# Step 1: Clone the repository using the project's Git URL
git clone <YOUR_GIT_URL>

# Step 2: Navigate to the project directory
cd <YOUR_PROJECT_NAME>

# Step 3: Install the necessary dependencies
npm install

# Step 4: Start the development server with auto-reloading
npm run dev
```

#### Option 2: Edit files directly in GitHub

- Navigate to the desired file(s)
- Click the "Edit" button (pencil icon) at the top right of the file view
- Make your changes and commit them

#### Option 3: Use GitHub Codespaces

- Navigate to the main page of your repository
- Click on the "Code" button (green button) near the top right
- Select the "Codespaces" tab
- Click on "New codespace" to launch a new Codespace environment
- Edit files directly within the Codespace and commit and push your changes

## 📦 Deployment

Deploying your project is simple with Lovable:

1. Open [Lovable](https://lovable.dev/projects/9b770523-569a-4669-8169-c4d98dfb5f45)
2. Navigate to Share -> Publish
3. Follow the on-screen instructions to complete the deployment

## 🔗 Custom Domain

Yes, you can connect a custom domain to your Lovable project!

To connect a domain:
1. Navigate to Project > Settings > Domains
2. Click "Connect Domain"
3. Follow the instructions to set up DNS records
4. Verify ownership and wait for DNS propagation

Read more here: [Setting up a custom domain](https://docs.lovable.dev/tips-tricks/custom-domain#step-by-step-guide)

## 📁 Project Structure

```
code-sentinel-bot/
├── public/          # Static assets
│   ├── components/  # UI components
│   ├── lib/         # Utility functions
│   ├── pages/       # Application pages
│   ├── styles/      # Global styles
│   ├── App.tsx      # Main application component
│   └── main.tsx     # Entry point
├── package.json     # Dependencies and scripts
└── README.md        # Project documentation
```

## 👥 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## 📄 License

This project is licensed under the MIT License - see the LICENSE file for details.


## Detected evidence (automated analysis)

Indexed codebase: 84 recognized source files, 356 KB.
- Anthropic (technology) — detected in the code
- CSS (language) — detected in the code
- Express (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- React (technology) — detected in the code
- Supabase (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Node.js (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (94 of 94)

```
.env.example
.gitignore
bun.lockb
components.json
eslint.config.js
index.html
package.json
postcss.config.js
public/robots.txt
README.md
server.js
src/App.css
src/App.tsx
src/components/__tests__/ArchitectureVisualization.test.tsx
src/components/__tests__/GitHubRepoInput.test.tsx
src/components/AnalyzationHistory.tsx
src/components/ArchitectureVisualization.tsx
src/components/GitHubRepoInput.tsx
src/components/PRAnalysisCard.tsx
src/components/RAGChatbot.tsx
src/components/RecommendationPanel.tsx
src/components/RepositoryInfo.tsx
src/components/RiskAssessment.tsx
src/components/SecurityAlert.tsx
src/components/ui/accordion.tsx
src/components/ui/alert-dialog.tsx
src/components/ui/alert.tsx
src/components/ui/aspect-ratio.tsx
src/components/ui/avatar.tsx
src/components/ui/badge.tsx
src/components/ui/breadcrumb.tsx
src/components/ui/button.tsx
src/components/ui/calendar.tsx
src/components/ui/card.tsx
src/components/ui/carousel.tsx
src/components/ui/chart.tsx
src/components/ui/checkbox.tsx
src/components/ui/collapsible.tsx
src/components/ui/command.tsx
src/components/ui/context-menu.tsx
src/components/ui/dialog.tsx
src/components/ui/drawer.tsx
src/components/ui/dropdown-menu.tsx
src/components/ui/form.tsx
src/components/ui/hover-card.tsx
src/components/ui/input-otp.tsx
src/components/ui/input.tsx
src/components/ui/label.tsx
src/components/ui/menubar.tsx
src/components/ui/navigation-menu.tsx
src/components/ui/pagination.tsx
src/components/ui/popover.tsx
src/components/ui/progress.tsx
src/components/ui/radio-group.tsx
src/components/ui/resizable.tsx
src/components/ui/scroll-area.tsx
src/components/ui/select.tsx
src/components/ui/separator.tsx
src/components/ui/sheet.tsx
src/components/ui/sidebar.tsx
src/components/ui/skeleton.tsx
src/components/ui/slider.tsx
src/components/ui/sonner.tsx
src/components/ui/switch.tsx
src/components/ui/table.tsx
src/components/ui/tabs.tsx
src/components/ui/textarea.tsx
src/components/ui/toast.tsx
src/components/ui/toaster.tsx
src/components/ui/toggle-group.tsx
src/components/ui/toggle.tsx
src/components/ui/tooltip.tsx
src/components/ui/use-toast.ts
src/hooks/use-mobile.tsx
src/hooks/use-toast.ts
src/index.css
src/integrations/supabase/client.ts
src/integrations/supabase/types.ts
src/lib/utils.ts
src/main.tsx
src/pages/Index.tsx
src/pages/NotFound.tsx
src/services/githubService.ts
src/services/ragService.ts
src/types/cosine-similarity.d.ts
src/vite-env.d.ts
supabase/config.toml
supabase/functions/analyze-repository/index.ts
supabase/functions/claude-chat/index.ts
tailwind.config.ts
tsconfig.app.json
tsconfig.json
tsconfig.node.json
vite.config.ts
```

### Dependencies

- package.json: @anthropic-ai/sdk@^0.24.3, @eslint/js@^9.9.0, @hookform/resolvers@^3.9.0, @octokit/rest@^20.0.2, @radix-ui/react-accordion@^1.2.0, @radix-ui/react-alert-dialog@^1.1.1, @radix-ui/react-aspect-ratio@^1.1.0, @radix-ui/react-avatar@^1.1.0, @radix-ui/react-checkbox@^1.1.1, @radix-ui/react-collapsible@^1.1.0, @radix-ui/react-context-menu@^2.2.1, @radix-ui/react-dialog@^1.1.2, @radix-ui/react-dropdown-menu@^2.1.1, @radix-ui/react-hover-card@^1.1.1, @radix-ui/react-label@^2.1.0, @radix-ui/react-menubar@^1.1.1, @radix-ui/react-navigation-menu@^1.2.0, @radix-ui/react-popover@^1.1.1, @radix-ui/react-progress@^1.1.0, @radix-ui/react-radio-group@^1.2.0, @radix-ui/react-scroll-area@^1.1.0, @radix-ui/react-select@^2.1.1, @radix-ui/react-separator@^1.1.0, @radix-ui/react-slider@^1.2.0, @radix-ui/react-slot@^1.1.0, @radix-ui/react-switch@^1.1.0, @radix-ui/react-tabs@^1.1.0, @radix-ui/react-toast@^1.2.1, @radix-ui/react-toggle@^1.1.0, @radix-ui/react-toggle-group@^1.1.0, @radix-ui/react-tooltip@^1.1.4, @supabase/supabase-js@^2.50.0, @tailwindcss/typography@^0.5.15, @tanstack/react-query@^5.56.2, @types/node@^22.5.5, @types/react@^18.3.3, @types/react-dom@^18.3.0, @vitejs/plugin-react-swc@^3.5.0, autoprefixer@^10.4.20, class-variance-authority@^0.7.1, clsx@^2.1.1, cmdk@^1.0.0, concurrently@^9.2.0, cors@^2.8.5, cosine-similarity@^1.0.1, date-fns@^3.6.0, dotenv@^16.5.0, embla-carousel-react@^8.3.0, eslint@^9.9.0, eslint-plugin-react-hooks@^5.1.0-rc.0, eslint-plugin-react-refresh@^0.4.9, express@^5.1.0, globals@^15.9.0, input-otp@^1.2.4, lovable-tagger@^1.1.7, lucide-react@^0.462.0, mermaid@^11.7.0, next-themes@^0.3.0, postcss@^8.4.47, react@^18.3.1, react-day-picker@^8.10.1, react-dom@^18.3.1, react-hook-form@^7.53.0, react-markdown@^9.0.1, react-resizable-panels@^2.1.3, react-router-dom@^6.26.2, recharts@^2.12.7, sonner@^1.5.0, tailwind-merge@^2.5.2, tailwindcss@^3.4.11, tailwindcss-animate@^1.0.7, typescript@^5.5.3, typescript-eslint@^8.0.1, vaul@^0.9.3, vite@^5.4.1, zod@^3.23.8

### Recent commits (newest first)

- commit changes
- added functionality to analyze the repositories, fixed ai analysis
- added api fixes and other functionalities
- Remove .env file containing secrets
- working rag component
- README.md beautified
- Complete UI dev cycle and GitHUB API and ANTHROPIC API Integrations with SUPABASE
- feat: Integrate API keys
- feat: Add .env file and use API keys
- Connect to Supabase project
- feat: Add repository input functionality
- Refactor: Initial project setup
- Use tech stack vite_react_shadcn_ts

## Key source files (fetched from GitHub, selected and truncated for size)

### package.json

```
{
  "name": "vite_react_shadcn_ts",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "build:dev": "vite build --mode development",
    "lint": "eslint .",
    "preview": "vite preview",
    "server": "node server.js",
    "dev:full": "concurrently \"npm run server\" \"npm run dev\""
  },
  "dependencies": {
    "@anthropic-ai/sdk": "^0.24.3",
    "@hookform/resolvers": "^3.9.0",
    "@octokit/rest": "^20.0.2",
    "@radix-ui/react-accordion": "^1.2.0",
    "@radix-ui/react-alert-dialog": "^1.1.1",
    "@radix-ui/react-aspect-ratio": "^1.1.0",
    "@radix-ui/react-avatar": "^1.1.0",
    "@radix-ui/react-checkbox": "^1.1.1",
    "@radix-ui/react-collapsible": "^1.1.0",
    "@radix-ui/react-context-menu": "^2.2.1",
    "@radix-ui/react-dialog": "^1.1.2",
    "@radix-ui/react-dropdown-menu": "^2.1.1",
    "@radix-ui/react-hover-card": "^1.1.1",
    "@radix-ui/react-label": "^2.1.0",
    "@radix-ui/react-menubar": "^1.1.1",
    "@radix-ui/react-navigation-menu": "^1.2.0",
    "@radix-ui/react-popover": "^1.1.1",
    "@radix-ui/react-progress": "^1.1.0",
    "@radix-ui/react-radio-group": "^1.2.0",
    "@radix-ui/react-scroll-area": "^1.1.0",
    "@radix-ui/react-select": "^2.1.1",
    "@radix-ui/react-separator": "^1.1.0",
    "@radix-ui/react-slider": "^1.2.0",
    "@radix-ui/react-slot": "^1.1.0",
    "@radix-ui/react-switch": "^1.1.0",
    "@radix-ui/react-tabs": "^1.1.0",
    "@radix-ui/react-toast": "^1.2.1",
    "@radix-ui/react-toggle": "^1.1.0",
    "@radix-ui/react-toggle-group": "^1.1.0",
    "@radix-ui/react-tooltip": "^1.1.4",
    "@supabase/supabase-js": "^2.50.0",
    "@tanstack/react-query": "^5.56.2",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "cmdk": "^1.0.0",
    "concurrently": "^9.2.0",
    "cors": "^2.8.5",
    "cosine-similarity": "^1.0.1",
    "date-fns": "^3.6.0",
    "dotenv": "^16.5.0",
    "embla-carousel-react": "^8.3.0",
    "express": "^5.1.0",
    "input-otp": "^1.2.4",
    "lucide-react": "^0.462.0",
    "mermaid": "^11.7.0",
    "next-themes": "^0.3.0",
    "react": "^18.3.1",
    "react-day-picker": "^8.10.1",
    "react-dom": "^18.3.1",
    "react-hook-form": "^7.53.0",
    "react-markdown": "^9.0.1",
    "react-resizable-panels": "^2.1.3",
    "react-router-dom": "^6.26.2",
    "recharts": "^2.12.7",
    "sonner": "^1.5.0",
    "tailwind-merge": "^2.5.2",
    "tailwindcss-animate": "^1.0.7",
    "vaul": "^0.9.3",
    "zod": "^3.23.8"
  },
  "devDependencies": {
    "@eslint/js": "^9.9.0",
    "@tailwindcss/typography": "^0.5.15",
    "@types/node": "^22.5.5",
    "@types/react": "^18.3.3",
    "@types/react-dom": "^18.3.0",
    "@vitejs/plugin-react-swc": "^3.5.0",
    "autoprefixer": "^10.4.20",
    "eslint": "^9.9.0",
    "eslint-plugin-react-hooks": "^5.1.0-rc.0",
    "eslint-plugin-react-refresh": "^0.4.9",
    "globals": "^15.9.0",
    "lovable-tagger": "^1.1.7",
    "postcss": "^8.4.47",
    "tailwindcss": "^3.4.11",
    "typescript": "^5.5.3",
    "typescript-eslint": "^8.0.1",
    "vite": "^5.4.1"
  }
}

```

### server.js

```javascript
import express from 'express';
import cors from 'cors';
import dotenv from 'dotenv';

// Load environment variables
dotenv.config();

const app = express();
const port = 3001;

// Middleware
app.use(cors());
app.use(express.json({ limit: '10mb' }));

// Claude API proxy endpoint
app.post('/api/claude', async (req, res) => {
  try {
    const { prompt, maxTokens = 2000 } = req.body;
    
    const apiKey = process.env.VITE_CLAUDE_API_KEY;
    if (!apiKey) {
      return res.status(500).json({
        success: false,
        error: 'Claude API key not configured'
      });
    }

    console.log(`Processing Claude request: ${prompt.length} characters`);

    const response = await fetch('https://api.anthropic.com/v1/messages', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': apiKey,
        'anthropic-version': '2023-06-01'
      },
      body: JSON.stringify({
        model: 'claude-3-5-sonnet-20240620',
        max_tokens: maxTokens,
        messages: [{ role: 'user', content: prompt }]
      })
    });

    if (!response.ok) {
      const errorText = await response.text();
      console.error(`Claude API error: ${response.status} - ${errorText}`);
      return res.status(response.status).json({
        success: false,
        error: `Claude API error: ${response.status} - ${errorText}`
      });
    }

    const data = await response.json();
    
    if (data.content && data.content[0] && data.content[0].type === 'text') {
      const responseText = data.content[0].text;
      console.log(`Claude response: ${responseText.length} characters`);
      
      return res.json({
        success: true,
        response: responseText
      });
    } else {
      console.error('Unexpected Claude response format:', data);
      return res.status(500).json({
        success: false,
        error: 'Unexpected response format from Claude API'
      });
    }

  } catch (error) {
    console.error('Error in Claude proxy:', error);
    return res.status(500).json({
      success: false,
      error: error.message || 'Internal server error'
    });
  }
});

// Health check endpoint
app.get('/api/health', (req, res) => {
  res.json({ status: 'ok', message: 'Claude proxy server is running' });
});

app.listen(port, () => {
  console.log(`🚀 Claude proxy server running on http://localhost:${port}`);
  console.log(`🔑 Claude API key configured: ${!!process.env.VITE_CLAUDE_API_KEY}`);
});
```

### src/main.tsx

```typescript
import { createRoot } from 'react-dom/client'
import App from './App.tsx'
import './index.css'

createRoot(document.getElementById("root")!).render(<App />);

```

### src/App.tsx

```typescript
import { Toaster } from "@/components/ui/toaster";
import { Toaster as Sonner } from "@/components/ui/sonner";
import { TooltipProvider } from "@/components/ui/tooltip";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Index from "./pages/Index";
import NotFound from "./pages/NotFound";

const queryClient = new QueryClient();

const App = () => (
  <QueryClientProvider client={queryClient}>
    <TooltipProvider>
      <Toaster />
      <Sonner />
      <BrowserRouter>
        <Routes>
          <Route path="/" element={<Index />} />
          {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
          <Route path="*" element={<NotFound />} />
        </Routes>
      </BrowserRouter>
    </TooltipProvider>
  </QueryClientProvider>
);

export default App;

```

### supabase/functions/claude-chat/index.ts

```typescript
import "https://deno.land/x/xhr@0.1.0/mod.ts";
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};

interface ChatRequest {
  prompt: string;
  maxTokens?: number;
}

serve(async (req) => {
  if (req.method === 'OPTIONS') {
    return new Response(null, { headers: corsHeaders });
  }

  try {
    const { prompt, maxTokens = 2000 }: ChatRequest = await req.json();
    
    const claudeApiKey = Deno.env.get('CLAUDE_API_KEY');
    
    if (!claudeApiKey) {
      throw new Error('Claude API key not configured');
    }

    console.log(`Processing chat request with prompt length: ${prompt.length}`);

    // Call Claude API
    const response = await fetch('https://api.anthropic.com/v1/messages', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': claudeApiKey,
        'anthropic-version': '2023-06-01'
      },
      body: JSON.stringify({
        model: 'claude-3-sonnet-20240229',
        max_tokens: maxTokens,
        messages: [{ role: 'user', content: prompt }]
      })
    });

    if (!response.ok) {
      const errorText = await response.text();
      console.error(`Claude API error: ${response.status} - ${errorText}`);
      throw new Error(`Claude API error: ${response.status}`);
    }

    const data = await response.json();
    
    if (data.content && data.content[0] && data.content[0].type === 'text') {
      const responseText = data.content[0].text;
      console.log(`Generated response: ${responseText.length} characters`);
      
      return new Response(JSON.stringify({
        success: true,
        response: responseText
      }), {
        headers: { ...corsHeaders, 'Content-Type': 'application/json' },
      });
    } else {
      throw new Error('Unexpected response format from Claude API');
    }

  } catch (error) {
    console.error('Error in claude-chat function:', error);
    return new Response(JSON.stringify({ 
      success: false,
      error: error.message
    }), {
      status: 500,
      headers: { ...corsHeaders, 'Content-Type': 'application/json' },
    });
  }
});
```

### src/pages/Index.tsx

```typescript
import React, { useState, useEffect } from 'react';
import { GitPullRequest, Shield, AlertTriangle, CheckCircle, X, Users, FileText, Code, Lock, Brain, History } from 'lucide-react';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Progress } from '@/components/ui/progress';
import { Separator } from '@/components/ui/separator';
import { PRAnalysisCard } from '@/components/PRAnalysisCard';
import { SecurityAlert } from '@/components/SecurityAlert';
import { RiskAssessment } from '@/components/RiskAssessment';
import { RecommendationPanel } from '@/components/RecommendationPanel';
import { GitHubRepoInput } from '@/components/GitHubRepoInput';
import { RepositoryInfo } from '@/components/RepositoryInfo';
import { AnalyzationHistory } from '@/components/AnalyzationHistory';
import { RAGChatbot } from '@/components/RAGChatbot';
import { ArchitectureVisualization } from '@/components/ArchitectureVisualization';
import { useToast } from '@/hooks/use-toast';

const Index = () => {
  const [selectedPR, setSelectedPR] = useState(0);
  const [currentRepository, setCurrentRepository] = useState<any>(null);
  const [currentPRs, setCurrentPRs] = useState<any[]>([]);
  const [analyzationHistory, setAnalyzationHistory] = useState<any[]>([]);
  const { toast } = useToast();
  
  // Show message when no repository is selected
  const showEmptyState = !currentRepository;
  
  // Use current PRs if available, otherwise empty array
  const mockPRs = currentPRs.length > 0 ? currentPRs : [];
  const currentPR = mockPRs[selectedPR];
  
  // Debug current PR data
  React.useEffect(() => {
    if (currentPR) {
      console.log('Current PR data:', currentPR);
      console.log('Additions:', currentPR.additions);
      console.log('Deletions:', currentPR.deletions);
      console.log('Files changed:', currentPR.filesChanged);
    }
  }, [currentPR]);

  const handleRepositoryAnalyzed = (repoData: any) => {
    console.log('Repository analyzed, received data:', repoData);
    console.log('Pull requests:', repoData.pullRequests);
    if (repoData.pullRequests && repoData.pullRequests.length > 0) {
      console.log('First PR data:', repoData.pullRequests[0]);
    }
    
    setCurrentRepository(repoData.repository);
    setCurrentPRs(repoData.pullRequests);
    setSelectedPR(0); // Select first PR
    
    // Add to analyzation history
    if (repoData.repository) {
      const newHistoryItem = {
        id: Date.now(),
        repository: repoData.repository,
        timestamp: new Date().toISOString(),
        prCount: repoData.pullRequests?.length || 0
      };
      
      setAnalyzationHistory(prev => [newHistoryItem, ...prev]);
      
      // Store in localStorage
      const history = JSON.parse(localStorage.getItem('analyzationHistory') || '[]');
      localStorage.setItem('analyzationHistory', JSON.stringify([newHistoryItem, ...history].slice(0, 10)));
    }
  };
  
  const handleAddDemoRepo = () => {
    // Create a demo repository entry
    const demoRepos = [
      {
        name: "react",
        owner: "facebook",
        url: "https://github.com/facebook/react",
        language: "JavaScript",
        stars: 212000,
        forks: 44500,
        openPRs: 3
      },
      {
        name: "vscode",
        owner: "microsoft",
        url: "https://github.com/microsoft/vscode",
        language: "TypeScript",
        stars: 152000,
        forks: 28300,
        openPRs: 5
      },
      {
        name: "tensorflow",
        owner: "tensorflow",
        url: "https://github.com/tensorflow/tensorflow",
        language: "C++",
        stars: 178000,
        forks: 89000,
        openPRs: 4
      }
    ];
    
    // Pick a random demo repo
    const randomRepo = demoRepos[Math.floor(Math.random() * demoRepos.length)];
    
    // Create a history item
    const demoHistoryItem = {
      id: Date.now(),
      repository: randomRepo,
      timestamp: new Date().toISOString(),
      prCount: randomRepo.openPRs
    };
    
    // Add to history
    setAnalyzationHistory(prev => [demoHistoryItem, ...prev]);
    
    // Store in localStorage
    const history = JSON.parse(localStorage.getItem('analyzationHistory') || '[]');
    localStorage.setItem('analyzationHistory', JSON.stringify([demoHistoryItem, ...history].slice(0, 10)));
    
    // Show toast notification
    toast({
      title: "Demo Repository Added",
      description: `Added ${randomRepo.name} by ${randomRepo.owner} to your history.`,
      variant: "default",
    });
  };

  // Load history from localStorage on component mount
  useEffect(() => {
    const savedHistory = localStorage.getItem('analyzationHistory');
    if (savedHistory) {
      setAnalyzationHistory(JSON.parse(savedHistory));
    }
  }, []);

  return (
    <div className="min-h-screen bg-gradient-to-br from-gray-950 via-slate-900 to-gray-950 relative overflow-hidden">
      {/* Animated background elements */}
      <div className="absolute inset-0 overflow-hidden">
        <div className="absolute -top-40 -right-40 w-80 h-80 bg-gradient-to-br from-purple-500/20 to-pink-500/20 rounded-full blur-3xl animate-pulse"></div>
        <div className="absolute -bottom-40 -left-40 w-80 h-80 bg-gradient-to-br from-blue-500/20 to-cyan-500/20 rounded-full blur-3xl animate-pulse delay-1000"></div>
        <div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-96 h-96 bg-gradient-to-br from-indigo-500/10 to-purple-500/10 rounded-full blur-3xl animate-pulse delay-500"></div>
      </div>

      {/* Header */}
      <div className="border-b border-gray-800/50 bg-gray-950/60 backdrop-blur-xl sticky top-0 z-50">
        <div className="max-w-7xl mx-auto px-6 py-4">
          <div className="flex items-center justify-between">
     
[truncated — 18534 more characters]
```

### supabase/functions/analyze-repository/index.ts

```typescript
import "https://deno.land/x/xhr@0.1.0/mod.ts";
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};

interface GitHubPR {
  id: number;
  number: number;
  title: string;
  user: { login: string };
  state: string;
  additions: number;
  deletions: number;
  changed_files: number;
  mergeable_state: string;
  html_url: string;
}

interface GitHubRepo {
  name: string;
  owner: { login: string };
  html_url: string;
  language: string;
  stargazers_count: number;
  forks_count: number;
}

// Handle Claude chat requests
async function handleClaudeChat(prompt: string, maxTokens: number = 2000) {
  const claudeToken = Deno.env.get('CLAUDE_API_KEY');
  
  console.log(`Claude token check: present=${!!claudeToken}, length=${claudeToken?.length || 0}`);
  
  if (!claudeToken) {
    throw new Error('Claude API key not configured');
  }

  console.log(`Processing Claude chat request with prompt length: ${prompt.length}`);

  try {
    const response = await fetch('https://api.anthropic.com/v1/messages', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': claudeToken,
        'anthropic-version': '2023-06-01'
      },
      body: JSON.stringify({
        model: 'claude-3-sonnet-20240229',
        max_tokens: maxTokens,
        messages: [{ role: 'user', content: prompt }]
      })
    });

    if (!response.ok) {
      const errorText = await response.text();
      console.error(`Claude API error: ${response.status} - ${errorText}`);
      throw new Error(`Claude API error: ${response.status}`);
    }

    const data = await response.json();
    
    if (data.content && data.content[0] && data.content[0].type === 'text') {
      const responseText = data.content[0].text;
      console.log(`Generated response: ${responseText.length} characters`);
      
      return new Response(JSON.stringify({
        success: true,
        response: responseText
      }), {
        headers: { ...corsHeaders, 'Content-Type': 'application/json' },
      });
    } else {
      throw new Error('Unexpected response format from Claude API');
    }
  } catch (error) {
    console.error('Error in Claude chat:', error);
    return new Response(JSON.stringify({ 
      success: false,
      error: error.message
    }), {
      status: 500,
      headers: { ...corsHeaders, 'Content-Type': 'application/json' },
    });
  }
}

serve(async (req) => {
  if (req.method === 'OPTIONS') {
    return new Response(null, { headers: corsHeaders });
  }

  try {
    const body = await req.json();
    const { repoUrl, chatPrompt, maxTokens } = body;
    
    // Handle Claude chat requests
    if (chatPrompt) {
      return await handleClaudeChat(chatPrompt, maxTokens);
    }
    
    const githubToken = Deno.env.get('GITHUB_API_KEY') || Deno.env.get('VITE_GITHUB_TOKEN');
    const claudeToken = Deno.env.get('CLAUDE_API_KEY');
    
    console.log(`Environment check: GitHub token present: ${!!githubToken}, Claude token present: ${!!claudeToken}`);
    console.log(`GitHub token starts with: ${githubToken ? githubToken.substring(0, 10) + '...' : 'N/A'}`);
    
    if (!githubToken) {
      throw new Error('GitHub API key not configured');
    }
    
    if (!claudeToken) {
      throw new Error('Claude API key not configured');
    }

    // Extract owner and repo from URL
    const urlParts = repoUrl.replace('https://github.com/', '').split('/');
    const owner = urlParts[0];
    const repo = urlParts[1];

    console.log(`Analyzing repository: ${owner}/${repo}`);

    // Fetch repository info
    const repoResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}`, {
      headers: {
        'Authorization': `Bearer ${githubToken}`,
        'Accept': 'application/vnd.github.v3+json',
        'User-Agent': 'PR-Guardian-AI',
      },
    });

    if (!repoResponse.ok) {
      if (repoResponse.status === 404) {
        throw new Error('Repository not found. Please check the URL and ensure the repository is public or you have access to it.');
      }
      throw new Error(`Failed to fetch repository: ${repoResponse.statusText}`);
    }

    const repoData: GitHubRepo = await repoResponse.json();

    // Fetch pull requests
    const prsResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}/pulls?state=open&per_page=10`, {
      headers: {
        'Authorization': `Bearer ${githubToken}`,
        'Accept': 'application/vnd.github.v3+json',
        'User-Agent': 'PR-Guardian-AI',
      },
    });

    if (!prsResponse.ok) {
      throw new Error(`Failed to fetch pull requests: ${prsResponse.statusText}`);
    }

    const prsData: GitHubPR[] = await prsResponse.json();

    if (prsData.length === 0) {
      return new Response(JSON.stringify({
        repository: {
          name: repoData.name,
          owner: repoData.owner.login,
          url: repoData.html_url,
          language: repoData.language || 'Unknown',
          stars: repoData.stargazers_count,
          forks: repoData.forks_count,
          openPRs: 0
        },
        pullRequests: []
      }), {
        headers: { ...corsHeaders, 'Content-Type': 'application/json' },
      });
    }

    // Analyze each PR with Claude
    const analyzedPRs = await Promise.all(
      prsData.slice(0, 5).map(async (pr) => {
        try {
          console.log(`Analyzing PR #${pr.number}: ${pr.title}`);
          
          // Fetch detailed PR info to get accurate additions/deletions
          const detailedPrResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}/pulls/${pr.number}`, {
            headers: {
              'Authorization': `Bearer ${githubToken}`,
              'Accept': 'application/vnd.github.v3+json',
              'User-Agent': 'PR-Guardian-AI',
            },
          });

          let detailedPrData = pr;
  
[truncated — 9459 more characters]
```

### postcss.config.js

```javascript
export default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

```

### vite.config.ts

```typescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import path from "path";
import { componentTagger } from "lovable-tagger";

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
  server: {
    host: "::",
    port: 8080,
  },
  plugins: [
    react(),
    mode === 'development' &&
    componentTagger(),
  ].filter(Boolean),
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
}));

```

### eslint.config.js

```javascript
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";

export default tseslint.config(
  { ignores: ["dist"] },
  {
    extends: [js.configs.recommended, ...tseslint.configs.recommended],
    files: ["**/*.{ts,tsx}"],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
    },
    plugins: {
      "react-hooks": reactHooks,
      "react-refresh": reactRefresh,
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      "react-refresh/only-export-components": [
        "warn",
        { allowConstantExport: true },
      ],
      "@typescript-eslint/no-unused-vars": "off",
    },
  }
);

```

[74 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]