diff --git a/FixArchonUIPortConfiguration.ps1 b/FixArchonUIPortConfiguration.ps1 new file mode 100644 index 0000000000..f105426aa3 --- /dev/null +++ b/FixArchonUIPortConfiguration.ps1 @@ -0,0 +1,37 @@ +# Fix Archon UI Port Configuration +# PowerShell script to fix the port mismatch issue + +param( + [string]$ResourceGroupName = "rg-archon" +) + +Write-Host "Fixing Archon UI port configuration..." -ForegroundColor Cyan + +# Update the target port to match what the container is listening on (5173) +Write-Host "Updating archon-ui to use port 5173..." -ForegroundColor Yellow + +try { + az containerapp update ` + --name "archon-ui" ` + --resource-group $ResourceGroupName ` + --target-port 5173 ` + --output none + + Write-Host "Port configuration updated successfully!" -ForegroundColor Green + Write-Host "The UI should now be accessible in a few minutes." -ForegroundColor Green +} catch { + Write-Host "Failed to update port configuration" -ForegroundColor Red + Write-Host "Trying alternative approaches..." -ForegroundColor Yellow +} + +# Get the updated URL +$uiUrl = az containerapp show --name "archon-ui" --resource-group $ResourceGroupName --query "properties.configuration.ingress.fqdn" --output tsv +$uiFullUrl = "https://$uiUrl" + +Write-Host "" +Write-Host "Updated UI URL: $uiFullUrl" -ForegroundColor Green +Write-Host "" +Write-Host "Next steps:" -ForegroundColor Cyan +Write-Host "1. Wait 2-3 minutes for the revision to update" +Write-Host "2. Check the container status in Azure Portal" +Write-Host "3. If still failing, we may need to rebuild the Docker image" \ No newline at end of file diff --git a/FixFrontendBackendURLs.ps1 b/FixFrontendBackendURLs.ps1 new file mode 100644 index 0000000000..7f28523cc7 --- /dev/null +++ b/FixFrontendBackendURLs.ps1 @@ -0,0 +1,19 @@ +# Fix Frontend Backend URLs +$serverUrl = az containerapp show --name "archon-server" --resource-group "rg-archon" --query "properties.configuration.ingress.fqdn" --output tsv +$mcpUrl = az containerapp show --name "archon-mcp" --resource-group "rg-archon" --query "properties.configuration.ingress.fqdn" --output tsv +$agentsUrl = az containerapp show --name "archon-agents" --resource-group "rg-archon" --query "properties.configuration.ingress.fqdn" --output tsv + +Write-Host "Updating frontend with backend URLs..." +Write-Host "Server: https://$serverUrl" +Write-Host "MCP: https://$mcpUrl" +Write-Host "Agents: https://$agentsUrl" + +az containerapp update ` + --name "archon-ui" ` + --resource-group "rg-archon" ` + --set-env-vars ` + "VITE_API_URL=https://$serverUrl" ` + "VITE_MCP_URL=https://$mcpUrl" ` + "VITE_AGENTS_URL=https://$agentsUrl" + +Write-Host "Frontend updated. Wait 2-3 minutes and refresh the page." \ No newline at end of file diff --git a/MCP-SERVER-FIX-README.md b/MCP-SERVER-FIX-README.md new file mode 100644 index 0000000000..794ed08790 --- /dev/null +++ b/MCP-SERVER-FIX-README.md @@ -0,0 +1,236 @@ +# MCP Server Fix for Azure Container Apps + +## Problem Summary + +Your MCP server was returning **404 Not Found** for health checks and **406 Not Acceptable** for MCP requests in Azure Container Apps. This was caused by: + +1. **Missing Health Endpoints**: The MCP server didn't have `/health` endpoints for Azure health checks +2. **Service Discovery Issues**: The server couldn't properly connect to other services in the Azure environment +3. **Environment Configuration**: Missing environment variables for Azure Container App deployment + +## What Was Fixed + +### 1. Added Health Endpoints to MCP Server +- **Root endpoint** (`/`): Returns service information +- **Health endpoint** (`/health`): Returns health status for Azure Container App health checks +- **MCP health endpoint** (`/mcp/health`): MCP-specific health check + +### 2. Fixed Service Discovery for Azure +- Added Azure environment detection (`CONTAINER_ENV=azure`) +- Updated service URLs to use external Azure Container App URLs +- Improved timeout handling for Azure network latency + +### 3. Enhanced MCP Service Client +- Better error logging with endpoint information +- Azure-specific timeout configurations +- Improved health check reliability + +## Files Modified + +### Core MCP Server +- `python/src/mcp/mcp_server.py` - Added FastAPI health endpoints and improved configuration + +### Service Discovery +- `python/src/server/config/service_discovery.py` - Added Azure environment support + +### MCP Service Client +- `python/src/server/services/mcp_service_client.py` - Enhanced Azure compatibility + +## How to Apply the Fix + +### Option 1: Quick Fix (Environment Variables Only) + +If you want to try fixing just the environment variables first: + +```powershell +# Run the quick fix script +.\quick-fix-mcp.ps1 +``` + +This will: +- Update the MCP server environment variables +- Configure proper service URLs +- Test the endpoints after restart + +### Option 2: Complete Fix (Rebuild + Deploy) + +For a complete fix that includes the code changes: + +```powershell +# Run the complete fix script +.\fix-mcp-server.ps1 -DockerUsername "yourusername" -SupabaseUrl "your-supabase-url" -SupabaseServiceKey "your-key" -OpenAIApiKey "your-openai-key" +``` + +This will: +- Build a new Docker image with the fixes +- Push it to Docker Hub +- Update the Azure Container App +- Configure all environment variables +- Test the endpoints + +### Option 3: Manual Fix + +If you prefer to apply the changes manually: + +1. **Update the MCP server environment variables**: +```bash +az containerapp update --name "archon-mcp" --resource-group "rg-archon" \ + --set-env-vars \ + "CONTAINER_ENV=azure" \ + "DEPLOYMENT_MODE=cloud" \ + "ARCHON_SERVER_PORT=8181" \ + "ARCHON_MCP_PORT=8051" \ + "ARCHON_AGENTS_PORT=8052" \ + "ARCHON_SERVER_URL=https://archon-server.purplemoss-0b16bcfe.eastus.azurecontainerapps.io" \ + "ARCHON_AGENTS_URL=https://archon-agents.purplemoss-0b16bcfe.eastus.azurecontainerapps.io" \ + "AZURE_CONTAINER_APPS_DOMAIN=purplemoss-0b16bcfe.eastus.azurecontainerapps.io" +``` + +2. **Rebuild and redeploy the MCP server** with the updated code + +## Testing the Fix + +### 1. Check Health Endpoints + +After applying the fix, test these endpoints: + +```bash +# Root endpoint +curl https://archon-mcp.purplemoss-0b16bcfe.eastus.azurecontainerapps.io/ + +# Health endpoint +curl https://archon-mcp.purplemoss-0b16bcfe.eastus.azurecontainerapps.io/health + +# MCP health endpoint +curl https://archon-mcp.purplemoss-0b16bcfe.eastus.azurecontainerapps.io/mcp/health +``` + +### 2. Check Azure Container App Logs + +```bash +az containerapp logs show --name "archon-mcp" --resource-group "rg-archon" --output table +``` + +Look for: +- ✅ "Health endpoints configured" +- ✅ "Service client initialized" +- ✅ No more 404/406 errors + +### 3. Test MCP Connection + +From your AI coding assistant, test the MCP connection: + +```json +{ + "mcpServers": { + "archon": { + "command": "npx", + "args": [ + "@modelcontextprotocol/server-fetch", + "https://archon-mcp.purplemoss-0b16bcfe.eastus.azurecontainerapps.io" + ] + } + } +} +``` + +## Expected Results + +After the fix, you should see: + +1. **Health checks passing** in Azure Container App +2. **No more 404/406 errors** in the logs +3. **Proper service communication** between MCP server and other services +4. **MCP tools working** from your AI coding assistant + +## Troubleshooting + +### If Health Endpoints Still Return 404 + +1. **Check if the MCP server restarted**: + ```bash + az containerapp revision list --name "archon-mcp" --resource-group "rg-archon" + ``` + +2. **Verify environment variables**: + ```bash + az containerapp show --name "archon-mcp" --resource-group "rg-archon" --query "properties.configuration.template.containers[0].env" + ``` + +3. **Check container logs** for startup errors: + ```bash + az containerapp logs show --name "archon-mcp" --resource-group "rg-archon" --output table + ``` + +### If Services Can't Communicate + +1. **Verify service URLs** are correct in the environment variables +2. **Check network policies** in Azure Container Apps +3. **Verify all services are running** and healthy + +### If MCP Tools Still Don't Work + +1. **Check MCP server logs** for tool registration errors +2. **Verify the MCP endpoint** is accessible +3. **Test with a simple MCP client** to isolate the issue + +## Environment Variables Reference + +### Required for MCP Server +- `CONTAINER_ENV=azure` - Enables Azure environment detection +- `DEPLOYMENT_MODE=cloud` - Sets cloud deployment mode +- `ARCHON_MCP_PORT=8051` - MCP server port +- `ARCHON_SERVER_PORT=8181` - API server port +- `ARCHON_AGENTS_PORT=8052` - Agents service port + +### Service URLs +- `ARCHON_SERVER_URL` - Full URL to the API server +- `ARCHON_AGENTS_URL` - Full URL to the agents service +- `AZURE_CONTAINER_APPS_DOMAIN` - Azure Container Apps domain + +### Database and API Keys +- `SUPABASE_URL` - Your Supabase project URL +- `SUPABASE_SERVICE_KEY` - Your Supabase service key +- `OPENAI_API_KEY` - Your OpenAI API key + +## Architecture Changes + +### Before (Broken) +``` +MCP Server (No health endpoints) + ↓ +Service Discovery (Docker-only) + ↓ +HTTP Calls (Internal URLs) +``` + +### After (Fixed) +``` +MCP Server (With health endpoints) + ↓ +Service Discovery (Azure-aware) + ↓ +HTTP Calls (External Azure URLs) +``` + +## Next Steps + +1. **Apply the fix** using one of the provided scripts +2. **Test the health endpoints** to verify they're working +3. **Test MCP tools** from your AI coding assistant +4. **Monitor logs** to ensure continued stability +5. **Update your MCP client configuration** with the working URL + +## Support + +If you continue to experience issues after applying these fixes: + +1. Check the Azure Container App logs for specific error messages +2. Verify all environment variables are set correctly +3. Ensure all dependent services (API server, agents) are healthy +4. Consider rebuilding the Docker image if environment variable changes don't resolve the issue + +The fixes address the core architectural issues that were preventing your MCP server from working properly in the Azure Container Apps environment. + + + diff --git a/Rebuild-ArchonUI-Env.ps1 b/Rebuild-ArchonUI-Env.ps1 new file mode 100644 index 0000000000..4e33884fd5 --- /dev/null +++ b/Rebuild-ArchonUI-Env.ps1 @@ -0,0 +1,89 @@ +# Rebuild Archon UI with proper environment variables +param( + [Parameter(Mandatory=$true)] + [string]$DockerUsername, + [string]$VersionTag = "env-fix" +) + +Write-Host "Rebuilding Archon UI with environment variables..." -ForegroundColor Cyan + +# Step 1: Create an .env file for the build +$envContent = @" +VITE_API_URL=https://archon-server.purplemoss-0b16bcfe.eastus.azurecontainerapps.io +VITE_MCP_URL=https://archon-mcp.purplemoss-0b16bcfe.eastus.azurecontainerapps.io +VITE_AGENTS_URL=https://archon-agents.purplemoss-0b16bcfe.eastus.azurecontainerapps.io +"@ + +$envContent | Out-File -FilePath ".\archon-ui-main\.env" -Encoding UTF8 +Write-Host "Created .env file with backend URLs" -ForegroundColor Green + +# Step 2: Create Dockerfile that uses environment variables during build +$dockerfile = @" +FROM node:18-alpine + +WORKDIR /app + +# Copy package files +COPY package*.json ./ + +# Install dependencies +RUN npm ci + +# Copy source code including .env +COPY . . + +# Set build-time environment variables +ARG VITE_API_URL=https://archon-server.purplemoss-0b16bcfe.eastus.azurecontainerapps.io +ARG VITE_MCP_URL=https://archon-mcp.purplemoss-0b16bcfe.eastus.azurecontainerapps.io +ARG VITE_AGENTS_URL=https://archon-agents.purplemoss-0b16bcfe.eastus.azurecontainerapps.io + +ENV VITE_API_URL=$VITE_API_URL +ENV VITE_MCP_URL=$VITE_MCP_URL +ENV VITE_AGENTS_URL=$VITE_AGENTS_URL + +# Build for production with environment variables +RUN npm run build + +# Install serve +RUN npm install -g serve + +# Expose port 5173 +EXPOSE 5173 + +# Serve static files +CMD ["serve", "-s", "dist", "-l", "5173"] +"@ + +$dockerfile | Out-File -FilePath ".\archon-ui-main\Dockerfile" -Encoding UTF8 +Write-Host "Created Dockerfile with environment variables" -ForegroundColor Green + +# Step 3: Build with build args +Write-Host "Building Docker image with environment variables..." -ForegroundColor Yellow + +docker build ` + --build-arg VITE_API_URL=https://archon-server.purplemoss-0b16bcfe.eastus.azurecontainerapps.io ` + --build-arg VITE_MCP_URL=https://archon-mcp.purplemoss-0b16bcfe.eastus.azurecontainerapps.io ` + --build-arg VITE_AGENTS_URL=https://archon-agents.purplemoss-0b16bcfe.eastus.azurecontainerapps.io ` + -t "$DockerUsername/archon-ui:$VersionTag" ` + ./archon-ui-main/ + +if ($LASTEXITCODE -eq 0) { + Write-Host "Docker build successful!" -ForegroundColor Green + + Write-Host "Pushing to Docker Hub..." -ForegroundColor Yellow + docker push "$DockerUsername/archon-ui:$VersionTag" + + if ($LASTEXITCODE -eq 0) { + Write-Host "Image pushed successfully!" -ForegroundColor Green + + Write-Host "Updating Azure Container App..." -ForegroundColor Yellow + az containerapp update ` + --name "archon-ui" ` + --resource-group "rg-archon" ` + --image "$DockerUsername/archon-ui:$VersionTag" + + Write-Host "Deployment complete! Wait 2-3 minutes and refresh your browser." -ForegroundColor Green + } +} else { + Write-Host "Docker build failed!" -ForegroundColor Red +} \ No newline at end of file diff --git a/Rebuild-ArchonUI.ps1 b/Rebuild-ArchonUI.ps1 new file mode 100644 index 0000000000..e926be4c44 --- /dev/null +++ b/Rebuild-ArchonUI.ps1 @@ -0,0 +1,160 @@ +# Rebuild Archon UI with proper production configuration +# PowerShell Script + +param( + [Parameter(Mandatory=$true)] + [string]$DockerUsername, + + [string]$VersionTag = "production", + [string]$ResourceGroupName = "rg-archon" +) + +Write-Host "Fixing Archon UI for Azure Container Apps..." -ForegroundColor Cyan + +# Step 1: Create fixed vite.config.js +Write-Host "Creating fixed vite.config.js..." -ForegroundColor Yellow + +$viteConfig = @" +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], + server: { + host: '0.0.0.0', + port: 5173, + allowedHosts: 'all' + }, + preview: { + host: '0.0.0.0', + port: 5173, + allowedHosts: 'all' + }, + build: { + outDir: 'dist', + sourcemap: false + } +}) +"@ + +$viteConfig | Out-File -FilePath ".\archon-ui-main\vite.config.js" -Encoding UTF8 + +# Step 2: Create production Dockerfile +Write-Host "Creating production Dockerfile..." -ForegroundColor Yellow + +$dockerfile = @" +FROM node:18-alpine + +WORKDIR /app + +# Copy package files +COPY package*.json ./ + +# Install dependencies +RUN npm ci + +# Copy source code +COPY . . + +# Build for production +RUN npm run build + +# Install serve +RUN npm install -g serve + +# Expose port 5173 +EXPOSE 5173 + +# Serve static files (not dev server) +CMD ["serve", "-s", "dist", "-l", "5173"] +"@ + +$dockerfile | Out-File -FilePath ".\archon-ui-main\Dockerfile" -Encoding UTF8 + +Write-Host "Configuration files created" -ForegroundColor Green + +# Step 3: Build and push new image +Write-Host "Building production image..." -ForegroundColor Yellow + +try { + # Build the Docker image + docker build -t "$DockerUsername/archon-ui:$VersionTag" ./archon-ui-main/ + + if ($LASTEXITCODE -ne 0) { + throw "Docker build failed" + } + + Write-Host "Pushing to Docker Hub..." -ForegroundColor Yellow + docker push "$DockerUsername/archon-ui:$VersionTag" + + if ($LASTEXITCODE -ne 0) { + throw "Docker push failed" + } + + Write-Host "New production image pushed: $DockerUsername/archon-ui:$VersionTag" -ForegroundColor Green + +} catch { + Write-Host "Failed to build or push Docker image: $_" -ForegroundColor Red + exit 1 +} + +# Step 4: Update Azure Container App +Write-Host "Updating Azure Container App..." -ForegroundColor Yellow + +try { + az containerapp update ` + --name "archon-ui" ` + --resource-group $ResourceGroupName ` + --image "$DockerUsername/archon-ui:$VersionTag" ` + --output none + + Write-Host "Azure Container App updated successfully!" -ForegroundColor Green + +} catch { + Write-Host "Failed to update Azure Container App: $_" -ForegroundColor Red + exit 1 +} + +# Step 5: Wait and check status +Write-Host "Waiting for deployment to complete..." -ForegroundColor Yellow +Start-Sleep -Seconds 30 + +$latestRevision = az containerapp show ` + --name "archon-ui" ` + --resource-group $ResourceGroupName ` + --query "properties.latestRevisionName" ` + --output tsv + +Write-Host "Latest revision: $latestRevision" -ForegroundColor Cyan + +# Get the URL +$uiUrl = az containerapp show ` + --name "archon-ui" ` + --resource-group $ResourceGroupName ` + --query "properties.configuration.ingress.fqdn" ` + --output tsv + +$uiFullUrl = "https://$uiUrl" + +Write-Host "" +Write-Host "Deployment Complete!" -ForegroundColor Green +Write-Host "===================" -ForegroundColor Green +Write-Host "" +Write-Host "UI URL: $uiFullUrl" -ForegroundColor Cyan +Write-Host "" +Write-Host "Next Steps:" -ForegroundColor Yellow +Write-Host "1. Wait 2-3 minutes for the new revision to be fully deployed" +Write-Host "2. Open the UI URL in your browser" +Write-Host "3. The Vite hostname restriction should now be resolved" +Write-Host "4. Configure your API keys in the UI settings" +Write-Host "" + +# Optional: Check the logs +$checkLogs = Read-Host "Would you like to check the container logs? (y/N)" +if ($checkLogs -eq "y" -or $checkLogs -eq "Y") { + Write-Host "Fetching recent logs..." -ForegroundColor Yellow + az containerapp logs show ` + --name "archon-ui" ` + --resource-group $ResourceGroupName ` + --tail 20 +} \ No newline at end of file diff --git a/SMART_CRAWLING_GUIDE.md b/SMART_CRAWLING_GUIDE.md new file mode 100644 index 0000000000..c6901c3335 --- /dev/null +++ b/SMART_CRAWLING_GUIDE.md @@ -0,0 +1,535 @@ +# 🚀 Smart Web Crawling System - Implementation Guide + +## Overview + +The Smart Web Crawling system is a comprehensive enhancement to Archon's existing crawling capabilities, providing specialized modes for different types of websites with advanced data extraction strategies. The system automatically detects website types and applies optimized crawling techniques for maximum data quality and relevance. + +## 🎯 Key Features + +### 1. **Automatic Website Detection** +- Intelligent analysis of HTML content, domain patterns, and metadata +- Multi-factor scoring system for accurate classification +- Confidence scoring and fallback mode recommendations +- Support for 10+ website types including e-commerce, blogs, documentation, analytics + +### 2. **E-commerce Specialized Crawling** +- **Advanced Product Data Extraction**: Name, description, SKU, brand, categories +- **Comprehensive Pricing Intelligence**: Current prices, original prices, discounts, currency +- **Product Variant Support**: Size, color, style options with individual pricing +- **Review and Rating Extraction**: Customer reviews, ratings, helpful votes +- **Inventory Tracking**: Stock status, availability, quantity information +- **Media Collection**: Product images, videos with full URL resolution +- **Specification Parsing**: Technical specifications, features, attributes + +### 3. **Price Intelligence & Competitive Analysis** +- Real-time price tracking with historical data +- Automated discount detection and calculation +- Brand comparison and market positioning analysis +- Price change alerts and trend analysis +- Competitive pricing intelligence + +### 4. **Multi-Mode Architecture** +- **E-commerce Mode**: Advanced product and pricing extraction +- **Blog Mode**: Article content, author info, publication metadata +- **Documentation Mode**: Technical content, API references, code examples +- **Analytics Mode**: Dashboard metrics, performance data extraction + +### 5. **MCP Integration** +- 6 specialized MCP tools for AI assistant integration +- Real-time crawling with progress tracking +- Product search and price intelligence queries +- Website type detection and recommendations + +## 🏗️ Architecture + +```mermaid +graph TB + subgraph "Smart Crawling System" + A[Smart Orchestrator] --> B[Website Detector] + A --> C[Mode Registry] + A --> D[Config Manager] + + B --> E[E-commerce Mode] + B --> F[Blog Mode] + B --> G[Documentation Mode] + B --> H[Analytics Mode] + + E --> I[Product Extractor] + E --> J[Price Tracker] + E --> K[Variant Analyzer] + + I --> L[Database Storage] + J --> M[Price History] + K --> N[Product Variants] + end + + subgraph "Data Storage" + L --> O[Products Table] + M --> P[Price History Table] + N --> Q[Variants Table] + R[Reviews Table] + S[Classifications Table] + end + + subgraph "API Layer" + T[Smart Crawl API] + U[E-commerce API] + V[Analytics API] + end + + subgraph "MCP Tools" + W[smart_crawl_website] + X[search_ecommerce_products] + Y[get_product_details] + Z[get_price_intelligence] + end +``` + +## 🚀 Getting Started + +### 1. Database Setup + +Run the Smart Crawling schema to create specialized tables: + +```sql +-- Execute in Supabase SQL Editor +-- File: migration/smart_crawling_modes_schema.sql +``` + +This creates: +- `archon_ecommerce_products` - Product data with pricing +- `archon_product_variants` - Product variants and options +- `archon_price_history` - Historical price tracking +- `archon_product_reviews` - Customer reviews and ratings +- `archon_website_classifications` - Website type detection results +- `archon_crawl_sessions` - Performance metrics and analytics + +### 2. Configuration + +The system automatically creates default configurations for each mode. Customize via API: + +```json +{ + "mode_name": "ecommerce", + "enabled": true, + "max_pages": 500, + "max_depth": 4, + "concurrent_requests": 3, + "delay_between_requests": 2.0, + "custom_settings": { + "extract_variants": true, + "extract_reviews": true, + "track_price_changes": true, + "max_images_per_product": 10 + } +} +``` + +## 📝 Usage Examples + +### 1. **Smart Crawling with Auto-Detection** + +```bash +# API Call +POST /api/smart-crawl/crawl +{ + "urls": [ + "https://amazon.com/dp/B08N5WRWNW", + "https://store.example.com/products" + ], + "source_id": "ecommerce-analysis-001", + "custom_config": { + "extract_reviews": true, + "track_price_changes": true + } +} + +# Response +{ + "success": true, + "progress_id": "uuid-here", + "message": "Smart crawling started successfully", + "urls_count": 2, + "estimated_time_minutes": 0.2 +} +``` + +### 2. **Website Type Detection** + +```bash +POST /api/smart-crawl/detect-website-type +{ + "url": "https://amazon.com" +} + +# Response +{ + "success": true, + "website_type": "ecommerce", + "confidence_score": 0.95, + "recommended_mode": "ecommerce", + "fallback_modes": ["analytics", "documentation"], + "indicators_found": [ + "content:add to cart", + "content:product-price", + "domain_match:.*amazon\\.com" + ] +} +``` + +### 3. **E-commerce Product Search** + +```bash +POST /api/smart-crawl/ecommerce/search +{ + "query": "wireless headphones", + "brand": "Sony", + "min_price": 50, + "max_price": 300, + "limit": 20 +} + +# Response +{ + "success": true, + "total_found": 15, + "products": [ + { + "id": "uuid", + "name": "Sony WH-1000XM4 Wireless Headphones", + "brand": "Sony", + "current_price": 249.99, + "original_price": 349.99, + "discount_percent": 28.57, + "rating": 4.5, + "review_count": 1250, + "in_stock": true, + "url": "https://..." + } + ] +} +``` + +### 4. **Price Intelligence Analysis** + +```bash +GET /api/smart-crawl/ecommerce/products?brand=Apple&days=30 + +# Analysis includes: +# - Price ranges and trends +# - Discount analysis +# - Brand comparison +# - Top discounts +# - Competitive positioning +``` + +## 🤖 MCP Tools Integration + +The system provides 6 specialized MCP tools for AI assistants: + +### 1. `smart_crawl_website` +```python +# Auto-detect and crawl with specialized modes +smart_crawl_website( + urls="https://amazon.com/dp/123,https://store.com/products", + source_id="competitive-analysis", + crawling_mode="auto", # or "ecommerce", "blog", etc. + extract_products=True, + extract_prices=True +) +``` + +### 2. `detect_website_type` +```python +# Analyze website and get recommendations +detect_website_type(url="https://shopify-store.com") +``` + +### 3. `search_ecommerce_products` +```python +# Search extracted products +search_ecommerce_products( + query="laptop gaming", + brand="ASUS", + min_price=800, + max_price=2000, + limit=10 +) +``` + +### 4. `get_product_details` +```python +# Get comprehensive product information +get_product_details(product_id="uuid-here") +``` + +### 5. `get_price_intelligence` +```python +# Competitive analysis and pricing insights +get_price_intelligence( + product_name="iPhone", + brand="Apple", + days=30 +) +``` + +### 6. `get_crawling_modes` +```python +# List available modes and configurations +get_crawling_modes() +``` + +## 🛠️ Advanced Configuration + +### Mode-Specific Settings + +#### E-commerce Mode +```json +{ + "extract_variants": true, + "extract_reviews": true, + "track_price_changes": true, + "max_images_per_product": 10, + "extract_specifications": true, + "bypass_cloudflare": true, + "wait_for_dynamic_content": true +} +``` + +#### Blog Mode +```json +{ + "extract_author": true, + "extract_publish_date": true, + "extract_tags": true, + "extract_comments": false, + "min_article_length": 300 +} +``` + +#### Documentation Mode +```json +{ + "extract_code_examples": true, + "extract_api_endpoints": true, + "follow_internal_links": true, + "extract_version_info": true +} +``` + +### Performance Tuning + +```json +{ + "concurrent_requests": 3, // Reduce for rate-limited sites + "delay_between_requests": 2.0, // Increase for respectful crawling + "max_retries": 3, + "timeout": 45000, // Longer for complex e-commerce pages + "use_random_user_agents": true, + "bypass_cloudflare": true +} +``` + +## 📊 Data Schema + +### E-commerce Products +```sql +-- Main product table +CREATE TABLE archon_ecommerce_products ( + id UUID PRIMARY KEY, + source_id TEXT NOT NULL, + url TEXT NOT NULL, + name TEXT, + brand TEXT, + current_price DECIMAL(10,2), + original_price DECIMAL(10,2), + discount_percent DECIMAL(5,2), + rating DECIMAL(3,2), + review_count INTEGER, + in_stock BOOLEAN, + specifications JSONB, + images JSONB, + -- ... additional fields +); +``` + +### Product Variants +```sql +CREATE TABLE archon_product_variants ( + id UUID PRIMARY KEY, + product_id UUID REFERENCES archon_ecommerce_products(id), + sku TEXT, + name TEXT, + attributes JSONB, -- {"size": "Large", "color": "Blue"} + price DECIMAL(10,2), + availability TEXT +); +``` + +### Price History +```sql +CREATE TABLE archon_price_history ( + id UUID PRIMARY KEY, + product_id UUID REFERENCES archon_ecommerce_products(id), + price DECIMAL(10,2) NOT NULL, + price_change_percent DECIMAL(5,2), + recorded_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() +); +``` + +## 🔍 Monitoring & Analytics + +### Performance Metrics +- Pages per second crawling rate +- Extraction success rates +- Data quality scores +- Mode detection accuracy +- Error rates and types + +### Real-time Progress Tracking +```javascript +// Socket.IO events for real-time updates +socket.on('crawl_progress', (data) => { + console.log(`Progress: ${data.percentage}%`); + console.log(`Status: ${data.status}`); + console.log(`Message: ${data.message}`); +}); +``` + +### Analytics Views +```sql +-- Price intelligence view +CREATE VIEW archon_product_price_intelligence AS +SELECT + p.name, + p.brand, + p.current_price, + p.discount_percent, + ph.price_change_percent, + s.source_id +FROM archon_ecommerce_products p +LEFT JOIN archon_sources s ON p.source_id = s.source_id +LEFT JOIN LATERAL ( + SELECT price_change_percent + FROM archon_price_history + WHERE product_id = p.id + ORDER BY recorded_at DESC + LIMIT 1 +) ph ON TRUE; +``` + +## 🚫 Anti-Bot Detection Features + +### Stealth Crawling +- Random user agent rotation +- Request timing randomization +- Browser fingerprint masking +- Cloudflare bypass capabilities +- Residential proxy support (configurable) + +### Respectful Crawling +- Robots.txt compliance +- Rate limiting and delays +- Graceful error handling +- Session management +- Memory usage optimization + +## 🎯 Use Cases + +### 1. **E-commerce Price Intelligence** +- Monitor competitor pricing +- Track product availability +- Analyze market trends +- Generate pricing reports +- Alert on price changes + +### 2. **Product Catalog Building** +- Extract comprehensive product data +- Build searchable catalogs +- Normalize product information +- Track inventory changes +- Generate product comparisons + +### 3. **Market Research** +- Competitive analysis +- Brand positioning studies +- Product feature comparisons +- Pricing strategy optimization +- Market trend identification + +### 4. **Content Aggregation** +- Blog post collection +- Documentation indexing +- News article extraction +- Technical content curation +- Knowledge base building + +## 🔧 Troubleshooting + +### Common Issues + +1. **Crawling Fails** + - Check website accessibility + - Verify crawler permissions + - Review rate limiting settings + - Check for anti-bot protections + +2. **Low Data Quality** + - Adjust extraction selectors + - Increase wait times for dynamic content + - Fine-tune mode configurations + - Review website structure changes + +3. **Performance Issues** + - Reduce concurrent requests + - Increase delays between requests + - Optimize memory usage + - Monitor resource consumption + +### Debug Mode +```json +{ + "custom_config": { + "debug_mode": true, + "save_html": true, + "verbose_logging": true + } +} +``` + +## 🚀 Future Enhancements + +### Planned Features +- **Additional Modes**: Social media, news, academic papers +- **Enhanced AI**: GPT-4 Vision for image-based extraction +- **Real-time Sync**: Live inventory and price updates +- **Advanced Analytics**: Predictive pricing models +- **API Integrations**: Direct e-commerce platform connections + +### Extensibility +The system is designed for easy extension: +- Create new mode classes inheriting from `BaseCrawlMode` +- Register modes in the `ModeRegistry` +- Add specialized extraction logic +- Configure database schemas +- Implement MCP tools + +## 📚 API Reference + +### Smart Crawling Endpoints +- `POST /api/smart-crawl/crawl` - Execute smart crawling +- `POST /api/smart-crawl/detect-website-type` - Detect website type +- `GET /api/smart-crawl/modes` - List crawling modes +- `PUT /api/smart-crawl/modes/{mode}/config` - Update mode config +- `POST /api/smart-crawl/cancel/{progress_id}` - Cancel crawling + +### E-commerce Endpoints +- `GET /api/smart-crawl/ecommerce/products` - List products +- `GET /api/smart-crawl/ecommerce/products/{id}` - Get product details +- `POST /api/smart-crawl/ecommerce/search` - Search products + +### Analytics Endpoints +- `GET /api/smart-crawl/analytics/sessions` - Crawling performance +- `GET /api/smart-crawl/analytics/trends` - Price and market trends + +This Smart Web Crawling system transforms Archon into a powerful, AI-ready platform for extracting structured data from the web with unprecedented accuracy and intelligence. The e-commerce specialization provides comprehensive product and pricing intelligence capabilities that enable sophisticated competitive analysis and market research workflows. \ No newline at end of file diff --git a/SPECIALIZED_CRAWLING.md b/SPECIALIZED_CRAWLING.md new file mode 100644 index 0000000000..32b7bf4d17 --- /dev/null +++ b/SPECIALIZED_CRAWLING.md @@ -0,0 +1,459 @@ +# Specialized Web Crawling System + +## Overview + +The Archon Specialized Crawling System extends the existing web crawling capabilities with intelligent, mode-based extraction strategies optimized for different website types. This system provides advanced e-commerce product intelligence, blog content extraction, documentation parsing, and more. + +## 🎯 Key Features + +### ✅ **Implemented Features** + +#### **Extensible Mode Architecture** +- **Base Mode Interface**: Abstract framework for creating specialized crawling modes +- **Mode Registry**: Centralized management and automatic mode selection +- **Configuration System**: Flexible, per-mode configuration management +- **Performance Tracking**: Real-time statistics and optimization metrics + +#### **Advanced E-commerce Mode** +- **Multi-Platform Support**: Amazon, Shopify, WooCommerce, Magento, and generic e-commerce +- **Product Data Extraction**: Name, brand, SKU, description, category +- **Pricing Intelligence**: Current price, original price, discounts, currency detection +- **Variant Analysis**: Size, color, style, material options +- **Review & Rating Extraction**: Customer feedback and rating aggregation +- **Inventory Status**: Stock availability and quantity tracking +- **Image Collection**: Product images and media assets +- **Technical Specifications**: Feature lists and technical details +- **Schema.org Support**: JSON-LD and microdata parsing +- **Competitive Intelligence**: Platform detection and marketing analysis + +#### **Intelligent Detection System** +- **URL Pattern Matching**: Regex and wildcard pattern support +- **Content Analysis**: HTML feature detection and confidence scoring +- **Domain Heuristics**: Platform-specific domain recognition +- **Automatic Fallback**: Graceful degradation to standard mode + +#### **Anti-Bot Detection & Stealth Crawling** +- **Enhanced Browser Configuration**: Optimized Chromium settings +- **User Agent Rotation**: Realistic browser identification +- **Dynamic Delay Injection**: Random timing to avoid detection patterns +- **Stealth Mode**: Advanced anti-detection techniques for e-commerce sites + +#### **Database Integration** +- **Structured Data Storage**: Dedicated tables for e-commerce products +- **Performance Tracking**: Mode usage statistics and success rates +- **Configuration Management**: Database-driven mode configuration +- **Version Control**: Schema versioning and migration support + +#### **API Endpoints** +- **Specialized Crawling**: `/api/crawling/specialized` - Mode-specific crawling +- **Mode Information**: `/api/crawling/modes` - Available modes and capabilities +- **Performance Metrics**: `/api/crawling/modes/{mode}/performance` - Usage statistics +- **E-commerce Search**: `/api/ecommerce/search` - Product data queries + +#### **MCP Tools Integration** +- **`crawl_ecommerce_site`**: Advanced e-commerce product extraction +- **`get_crawling_modes`**: Available modes and capabilities +- **`get_mode_performance`**: Performance statistics and metrics +- **`search_ecommerce_products`**: Product database queries with filters +- **`crawl_with_mode`**: Force-specific mode crawling +- **`get_product_by_url`**: Cached product data retrieval + +### 🚧 **Planned Features** + +#### **Blog & Content Mode** +- Article extraction with author and publication date +- Tag and category detection +- Social media metadata parsing +- Comment and engagement metrics + +#### **Documentation Mode** +- Enhanced code example extraction +- API reference parsing +- Navigation structure mapping +- Version detection and cross-referencing + +#### **News & Media Mode** +- Headline and byline extraction +- Publication information and timestamps +- Related article discovery +- Media asset collection + +#### **Analytics & Insights Mode** +- Performance metric extraction +- Dashboard data parsing +- Chart and graph data extraction +- KPI identification and tracking + +## 🏗️ Architecture + +### **Mode-Based Design Pattern** + +```mermaid +graph TB + subgraph "Crawling Request" + A[URL Input] --> B[Mode Detection] + B --> C{Mode Available?} + end + + subgraph "Mode Registry" + C -->|Yes| D[Get Mode Instance] + C -->|No| E[Standard Mode] + D --> F[Mode-Specific Config] + E --> G[Standard Config] + end + + subgraph "Extraction Pipeline" + F --> H[Specialized Crawler] + G --> H + H --> I[Content Analysis] + I --> J[Data Extraction] + J --> K[Post Processing] + end + + subgraph "Storage & Output" + K --> L[Structured Data] + K --> M[Standard Content] + L --> N[Specialized Tables] + M --> O[Knowledge Base] + end +``` + +### **Component Structure** + +``` +python/src/server/services/crawling/modes/ +├── base_mode.py # Abstract base class and interfaces +├── mode_registry.py # Mode management and selection +├── standard_mode.py # Default fallback mode +├── ecommerce_mode.py # E-commerce specialized mode +└── __init__.py # Package initialization and registration +``` + +### **Database Schema Enhancement** + +```sql +-- Core Tables +archon_ecommerce_products # Product data with pricing and variants +archon_crawling_modes # Mode configuration and settings +archon_crawling_performance # Usage statistics and metrics +archon_structured_data # Generic structured data storage + +-- Enhanced Existing Tables +archon_sources # Added crawling_mode and extraction_stats +``` + +## 🚀 Usage Examples + +### **API Usage** + +#### **E-commerce Product Extraction** +```bash +curl -X POST "http://localhost:8181/api/crawling/specialized" \ + -H "Content-Type: application/json" \ + -d '{ + "url": "https://amazon.com/dp/B08N5WRWNW", + "mode": "ecommerce", + "extract_pricing": true, + "extract_variants": true, + "anti_bot_mode": true + }' +``` + +#### **Get Available Modes** +```bash +curl "http://localhost:8181/api/crawling/modes" +``` + +#### **Mode Performance Statistics** +```bash +curl "http://localhost:8181/api/crawling/modes/ecommerce/performance" +``` + +### **MCP Tools Usage** + +#### **E-commerce Site Crawling** +```python +# Via MCP client (Claude, Cursor, etc.) +result = await mcp.call_tool("crawl_ecommerce_site", { + "url": "https://shopify-store.com/products/wireless-headphones", + "extract_pricing": True, + "extract_variants": True, + "anti_bot_mode": True +}) +``` + +#### **Product Search** +```python +products = await mcp.call_tool("search_ecommerce_products", { + "query": "wireless headphones", + "price_min": 50.0, + "price_max": 200.0, + "brand": "Sony", + "match_count": 10 +}) +``` + +#### **Mode Information** +```python +modes = await mcp.call_tool("get_crawling_modes") +performance = await mcp.call_tool("get_mode_performance", {"mode": "ecommerce"}) +``` + +### **Direct Service Usage** + +```python +from src.server.services.crawling import CrawlingService +from src.server.services.crawling.modes import CrawlingMode + +# Initialize with specialized modes +crawler = await get_crawler() +service = CrawlingService(crawler) + +# E-commerce crawling +result = await service.crawl_with_specialized_mode( + url="https://ecommerce-site.com/product/123", + force_mode="ecommerce", + extract_structured_data=True, + anti_bot_mode=True +) + +# Get available modes +modes = service.get_available_crawling_modes() + +# Performance statistics +stats = service.get_mode_performance_stats("ecommerce") +``` + +## 📊 Data Structures + +### **Product Data Schema** +```python +@dataclass +class ProductData: + name: str # Product name/title + brand: str # Brand or manufacturer + sku: str # Product SKU/ID + description: str # Product description + price_current: Optional[Decimal] # Current selling price + price_original: Optional[Decimal] # Original/MSRP price + currency: str # Price currency (USD, EUR, etc.) + availability: str # Stock status + rating: Optional[float] # Average rating (0-5) + review_count: int # Number of reviews + images: List[str] # Product image URLs + variants: List[Dict[str, Any]] # Size, color, style options + specifications: Dict[str, str] # Technical specifications +``` + +### **Crawling Result Structure** +```python +@dataclass +class CrawlingResult: + success: bool # Operation success status + url: str # Crawled URL + mode: str # Mode used for crawling + content: Dict[str, Any] # Extracted content (markdown, HTML) + metadata: Dict[str, Any] # Crawling metadata + structured_data: Dict[str, Any] # Mode-specific extracted data + error: Optional[str] # Error message if failed + extraction_stats: Dict[str, Any] # Extraction statistics +``` + +### **Mode Configuration** +```python +@dataclass +class ModeConfiguration: + mode: CrawlingMode # Mode identifier + enabled: bool # Whether mode is active + wait_strategy: str # Page load strategy + page_timeout: int # Maximum wait time + delay_before_html: float # Pre-extraction delay + max_retries: int # Retry attempts + stealth_mode: bool # Anti-detection features + extract_structured_data: bool # Enable data extraction + custom_selectors: Dict[str, str] # CSS selectors + mode_config: Dict[str, Any] # Mode-specific settings +``` + +## 🔧 Configuration + +### **Environment Variables** +```bash +# Enable specialized crawling features +SPECIALIZED_CRAWLING_ENABLED=true + +# E-commerce specific settings +ECOMMERCE_MODE_ENABLED=true +ECOMMERCE_STEALTH_MODE=true +ECOMMERCE_MAX_RETRIES=3 + +# Performance settings +CRAWL_BATCH_SIZE=50 +CRAWL_MAX_CONCURRENT=10 +CRAWL_PAGE_TIMEOUT=45000 +``` + +### **Database Configuration** +```sql +-- Enable e-commerce mode +INSERT INTO archon_crawling_modes (mode_name, enabled, mode_config) VALUES +('ecommerce', true, '{ + "extract_pricing": true, + "extract_reviews": true, + "extract_variants": true, + "stealth_mode": true, + "page_timeout": 45000 +}'); + +-- Configure URL patterns for auto-detection +UPDATE archon_crawling_modes +SET url_patterns = '[ + "regex:amazon\\.", + "regex:shopify\\.", + "regex:/product/", + "regex:/item/" +]' +WHERE mode_name = 'ecommerce'; +``` + +## 🧪 Testing & Validation + +### **E-commerce Test Sites** +```python +# Test URLs for different platforms +test_sites = { + "amazon": "https://amazon.com/dp/B08N5WRWNW", + "shopify": "https://shop.example.com/products/test-product", + "generic": "https://ecommerce-site.com/product/123" +} + +# Validation criteria +validation_checks = [ + "product_name_extracted", + "price_detected", + "availability_status", + "images_found", + "structured_data_valid" +] +``` + +### **Performance Monitoring** +```python +# Monitor mode performance +performance_metrics = { + "success_rate": "percentage of successful extractions", + "average_response_time": "crawling speed in seconds", + "data_completeness": "percentage of fields extracted", + "error_rate": "percentage of failed attempts" +} +``` + +## 🛠️ Extending the System + +### **Adding New Modes** + +1. **Create Mode Class** +```python +class BlogCrawlingMode(BaseCrawlingMode): + def _initialize_mode(self): + # Mode-specific initialization + pass + + async def can_handle_url(self, url: str) -> bool: + # URL compatibility check + return "blog" in url or "/post/" in url + + async def extract_structured_data(self, url: str, html: str, markdown: str): + # Blog-specific data extraction + return {"article": article_data, "author": author_info} +``` + +2. **Register Mode** +```python +# In modes/__init__.py +blog_config = ModeConfiguration(mode=CrawlingMode.BLOG, enabled=True) +registry.register_mode(CrawlingMode.BLOG, BlogCrawlingMode, blog_config) +``` + +3. **Add URL Patterns** +```sql +INSERT INTO archon_crawling_modes (mode_name, url_patterns) VALUES +('blog', '["regex:/blog/", "regex:/post/", "regex:wordpress\\."]'); +``` + +### **Custom Selectors** +```python +# Platform-specific CSS selectors +custom_selectors = { + "shopify": { + "name": ".product-title, .product__title", + "price": ".price, .product-price", + "availability": ".stock-status" + } +} +``` + +## 📈 Performance Optimization + +### **Crawling Efficiency** +- **Parallel Processing**: Concurrent mode execution +- **Intelligent Caching**: Mode-specific cache strategies +- **Resource Optimization**: Selective content loading +- **Error Recovery**: Graceful degradation and retry logic + +### **Data Storage Optimization** +- **Indexed Queries**: Optimized database indexes for fast lookup +- **Compression**: JSON data compression for large objects +- **Partitioning**: Date-based table partitioning for performance +- **Cleanup**: Automated old data removal and archiving + +## 🔒 Security & Privacy + +### **Anti-Detection Measures** +- **Browser Fingerprinting**: Realistic browser signatures +- **Request Throttling**: Human-like browsing patterns +- **IP Rotation**: Distributed crawling support +- **Header Randomization**: Dynamic request headers + +### **Data Privacy** +- **PII Filtering**: Automatic removal of personal information +- **Data Retention**: Configurable retention policies +- **Access Control**: Role-based data access restrictions +- **Audit Logging**: Complete activity tracking + +## 🚀 Deployment + +### **Database Migration** +```bash +# Run the specialized crawling schema migration +psql -f migration/add_specialized_crawling_tables.sql +``` + +### **Service Restart** +```bash +# Restart services to load new modes +docker-compose restart archon-server archon-mcp +``` + +### **Verification** +```bash +# Test mode availability +curl "http://localhost:8181/api/crawling/modes" + +# Test e-commerce crawling +curl -X POST "http://localhost:8181/api/crawling/specialized" \ + -H "Content-Type: application/json" \ + -d '{"url": "https://example-store.com/product", "mode": "ecommerce"}' +``` + +## 📚 Additional Resources + +- **API Documentation**: `/api/docs` - Interactive API documentation +- **Database Schema**: `migration/add_specialized_crawling_tables.sql` +- **Configuration Examples**: Environment variable templates +- **Performance Tuning**: Best practices and optimization guides + +--- + +**Status**: ✅ **Production Ready** - E-commerce mode fully implemented and tested +**Next Steps**: Blog mode, Documentation mode, Analytics mode implementation \ No newline at end of file diff --git a/archon-azure-setup.ps1 b/archon-azure-setup.ps1 new file mode 100644 index 0000000000..3135cff8b3 --- /dev/null +++ b/archon-azure-setup.ps1 @@ -0,0 +1,337 @@ +# Deploy Archon to Azure Container Apps +# PowerShell Script for complete deployment + +param( + [Parameter(Mandatory=$true)] + [string]$DockerUsername, + + [Parameter(Mandatory=$true)] + [string]$SupabaseUrl, + + [Parameter(Mandatory=$true)] + [string]$SupabaseServiceKey, + + [Parameter(Mandatory=$true)] + [string]$OpenAIApiKey, + + [string]$ResourceGroupName = "rg-archon", + [string]$Location = "East US", + [string]$EnvironmentName = "archon-env", + [string]$ImageTag = "latest" +) + +# Color functions for output +function Write-ColorOutput($ForegroundColor) { + $fc = $host.UI.RawUI.ForegroundColor + $host.UI.RawUI.ForegroundColor = $ForegroundColor + if ($args) { + Write-Output $args + } + else { + $input | Write-Output + } + $host.UI.RawUI.ForegroundColor = $fc +} + +function Write-Success { Write-ColorOutput Green @args } +function Write-Info { Write-ColorOutput Cyan @args } +function Write-Warning { Write-ColorOutput Yellow @args } +function Write-Error { Write-ColorOutput Red @args } + +# Header +Write-Info "=========================================" +Write-Info " Archon Azure Container Apps " +Write-Info " Deployment Script " +Write-Info "=========================================" +Write-Info "" + +# Validate Azure CLI +try { + $azVersion = az version --output tsv --query '"azure-cli"' 2>$null + Write-Success "Azure CLI version: $azVersion" +} catch { + Write-Error "Azure CLI not found. Please install Azure CLI first." + exit 1 +} + +# Check if logged in +try { + $account = az account show --output tsv --query 'name' 2>$null + Write-Success "Logged in to Azure account: $account" +} catch { + Write-Error "Not logged in to Azure. Please run 'az login' first." + exit 1 +} + +Write-Info "Deployment Configuration:" +Write-Info " Resource Group: $ResourceGroupName" +Write-Info " Location: $Location" +Write-Info " Environment: $EnvironmentName" +Write-Info " Docker Images: $DockerUsername/archon-*:$ImageTag" +Write-Info "" + +# Confirm deployment +$confirm = Read-Host "Continue with deployment? (y/N)" +if ($confirm -ne "y" -and $confirm -ne "Y") { + Write-Warning "Deployment cancelled by user." + exit 0 +} + +Write-Info "Starting deployment..." + +# Step 1: Create Resource Group +Write-Info "Creating resource group..." +try { + az group create --name $ResourceGroupName --location $Location --output none + Write-Success "Resource group '$ResourceGroupName' created/updated" +} catch { + Write-Error "Failed to create resource group" + exit 1 +} + +# Step 2: Create Container Apps Environment +Write-Info "Creating Container Apps environment..." +try { + az containerapp env create ` + --name $EnvironmentName ` + --resource-group $ResourceGroupName ` + --location $Location ` + --output none + Write-Success "Container Apps environment '$EnvironmentName' created" +} catch { + Write-Error "Failed to create Container Apps environment" + exit 1 +} + +# Step 3: Deploy Archon Server (Backend API) +Write-Info "Deploying Archon Server..." +try { + az containerapp create ` + --name "archon-server" ` + --resource-group $ResourceGroupName ` + --environment $EnvironmentName ` + --image "$DockerUsername/archon-server:$ImageTag" ` + --target-port 8181 ` + --ingress external ` + --env-vars ` + "SUPABASE_URL=$SupabaseUrl" ` + "SUPABASE_SERVICE_KEY=$SupabaseServiceKey" ` + "OPENAI_API_KEY=$OpenAIApiKey" ` + "HOST=0.0.0.0" ` + "PORT=8181" ` + --cpu 1.0 ` + --memory 2Gi ` + --min-replicas 1 ` + --max-replicas 3 ` + --output none + Write-Success "Archon Server deployed" +} catch { + Write-Error "Failed to deploy Archon Server" + exit 1 +} + +# Get Server URL +$serverUrl = az containerapp show --name "archon-server" --resource-group $ResourceGroupName --query "properties.configuration.ingress.fqdn" --output tsv +$serverFullUrl = "https://$serverUrl" +Write-Info "Server URL: $serverFullUrl" + +# Step 4: Deploy MCP Server +Write-Info "Deploying MCP Server..." +try { + az containerapp create ` + --name "archon-mcp" ` + --resource-group $ResourceGroupName ` + --environment $EnvironmentName ` + --image "$DockerUsername/archon-mcp:$ImageTag" ` + --target-port 8051 ` + --ingress external ` + --env-vars ` + "SUPABASE_URL=$SupabaseUrl" ` + "SUPABASE_SERVICE_KEY=$SupabaseServiceKey" ` + "ARCHON_SERVER_URL=$serverFullUrl" ` + "HOST=0.0.0.0" ` + "PORT=8051" ` + --cpu 0.5 ` + --memory 1Gi ` + --min-replicas 1 ` + --max-replicas 2 ` + --output none + Write-Success "MCP Server deployed" +} catch { + Write-Error "Failed to deploy MCP Server" + exit 1 +} + +# Get MCP URL +$mcpUrl = az containerapp show --name "archon-mcp" --resource-group $ResourceGroupName --query "properties.configuration.ingress.fqdn" --output tsv +$mcpFullUrl = "https://$mcpUrl" +Write-Info "MCP URL: $mcpFullUrl" + +# Step 5: Deploy Agents Service +Write-Info "Deploying Agents Service..." +try { + az containerapp create ` + --name "archon-agents" ` + --resource-group $ResourceGroupName ` + --environment $EnvironmentName ` + --image "$DockerUsername/archon-agents:$ImageTag" ` + --target-port 8052 ` + --ingress external ` + --env-vars ` + "SUPABASE_URL=$SupabaseUrl" ` + "SUPABASE_SERVICE_KEY=$SupabaseServiceKey" ` + "OPENAI_API_KEY=$OpenAIApiKey" ` + "ARCHON_SERVER_URL=$serverFullUrl" ` + "HOST=0.0.0.0" ` + "PORT=8052" ` + --cpu 1.0 ` + --memory 2Gi ` + --min-replicas 1 ` + --max-replicas 2 ` + --output none + Write-Success "Agents Service deployed" +} catch { + Write-Error "Failed to deploy Agents Service" + exit 1 +} + +# Get Agents URL +$agentsUrl = az containerapp show --name "archon-agents" --resource-group $ResourceGroupName --query "properties.configuration.ingress.fqdn" --output tsv +$agentsFullUrl = "https://$agentsUrl" +Write-Info "Agents URL: $agentsFullUrl" + +# Step 6: Deploy Frontend UI +Write-Info "Deploying Frontend UI..." +try { + az containerapp create ` + --name "archon-ui" ` + --resource-group $ResourceGroupName ` + --environment $EnvironmentName ` + --image "$DockerUsername/archon-ui:$ImageTag" ` + --target-port 3737 ` + --ingress external ` + --env-vars ` + "VITE_API_URL=$serverFullUrl" ` + "VITE_MCP_URL=$mcpFullUrl" ` + "VITE_AGENTS_URL=$agentsFullUrl" ` + "HOST=0.0.0.0" ` + "PORT=3737" ` + --cpu 0.5 ` + --memory 1Gi ` + --min-replicas 1 ` + --max-replicas 2 ` + --output none + Write-Success "Frontend UI deployed" +} catch { + Write-Error "Failed to deploy Frontend UI" + exit 1 +} + +# Get UI URL +$uiUrl = az containerapp show --name "archon-ui" --resource-group $ResourceGroupName --query "properties.configuration.ingress.fqdn" --output tsv +$uiFullUrl = "https://$uiUrl" + +# Step 7: Configure CORS for Server +Write-Info "Configuring CORS..." +try { + az containerapp update ` + --name "archon-server" ` + --resource-group $ResourceGroupName ` + --set-env-vars ` + "CORS_ORIGINS=$uiFullUrl" ` + --output none + Write-Success "CORS configured for server" +} catch { + Write-Warning "CORS configuration failed (non-critical)" +} + +# Step 8: Setup Application Insights (Optional) +Write-Info "Setting up Application Insights..." +try { + az monitor app-insights component create ` + --app "archon-insights" ` + --location $Location ` + --resource-group $ResourceGroupName ` + --output none + + $instrumentationKey = az monitor app-insights component show ` + --app "archon-insights" ` + --resource-group $ResourceGroupName ` + --query "instrumentationKey" ` + --output tsv + + # Update all apps with monitoring + $apps = @("archon-server", "archon-mcp", "archon-agents", "archon-ui") + foreach ($app in $apps) { + az containerapp update ` + --name $app ` + --resource-group $ResourceGroupName ` + --set-env-vars ` + "APPLICATIONINSIGHTS_CONNECTION_STRING=InstrumentationKey=$instrumentationKey" ` + --output none + } + Write-Success "Application Insights configured" +} catch { + Write-Warning "Application Insights setup failed (optional feature)" +} + +# Deployment Summary +Write-Success "" +Write-Success "Archon Deployment Completed Successfully!" +Write-Success "=========================================" +Write-Success "" +Write-Success "Access URLs:" +Write-Success " Frontend UI: $uiFullUrl" +Write-Success " Server API: $serverFullUrl" +Write-Success " MCP Server: $mcpFullUrl" +Write-Success " Agents: $agentsFullUrl" +Write-Success "" +Write-Info "Next Steps:" +Write-Info " 1. Open the Frontend UI and configure your API keys" +Write-Info " 2. Test by uploading a document or crawling a website" +Write-Info " 3. Configure your AI coding assistant with the MCP URL" +Write-Info "" +Write-Info "MCP Configuration for AI Clients:" +$mcpConfig = @" +{ + "mcpServers": { + "archon": { + "command": "npx", + "args": [ + "@modelcontextprotocol/server-fetch", + "$mcpFullUrl" + ] + } + } +} +"@ +Write-Info $mcpConfig +Write-Info "" +Write-Info "Cost Monitoring:" +Write-Info " View costs: https://portal.azure.com/#blade/Microsoft_Azure_CostManagement" +Write-Info " Set budgets: az consumption budget create --help" +Write-Info "" + +# Save deployment info to file +$deploymentInfo = @{ + "DeploymentDate" = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + "ResourceGroup" = $ResourceGroupName + "Environment" = $EnvironmentName + "URLs" = @{ + "Frontend" = $uiFullUrl + "Server" = $serverFullUrl + "MCP" = $mcpFullUrl + "Agents" = $agentsFullUrl + } + "DockerImages" = @{ + "UI" = "$DockerUsername/archon-ui:$ImageTag" + "Server" = "$DockerUsername/archon-server:$ImageTag" + "MCP" = "$DockerUsername/archon-mcp:$ImageTag" + "Agents" = "$DockerUsername/archon-agents:$ImageTag" + } +} + +$deploymentInfo | ConvertTo-Json -Depth 3 | Out-File "archon-deployment-info.json" +Write-Info "Deployment details saved to: archon-deployment-info.json" + +Write-Success "Your Archon AI platform is now live and ready for use!" \ No newline at end of file diff --git a/archon-deployment-info.json b/archon-deployment-info.json new file mode 100644 index 0000000000..1bc324d44e Binary files /dev/null and b/archon-deployment-info.json differ diff --git a/archon-ui-main/Dockerfile b/archon-ui-main/Dockerfile index 2ad5d5ff0f..24930f9f81 100644 --- a/archon-ui-main/Dockerfile +++ b/archon-ui-main/Dockerfile @@ -1,25 +1,17 @@ -# Simple Vite dev server setup -FROM node:18-alpine - +FROM node:18-alpine as builder WORKDIR /app - -# Install system dependencies needed for some npm packages -RUN apk add --no-cache python3 make g++ git curl - -# Copy package files COPY package*.json ./ - -# Install dependencies including dev dependencies for testing RUN npm ci - -# Create coverage directory with proper permissions -RUN mkdir -p /app/coverage && chmod 777 /app/coverage - -# Copy source code COPY . . - -# Expose Vite's default port +RUN npm run build + +FROM nginx:alpine +RUN apk add --no-cache gettext +COPY --from=builder /app/dist /usr/share/nginx/html +COPY nginx.conf.template /etc/nginx/conf.d/default.conf.template +COPY entrypoint.sh /docker-entrypoint.sh +RUN chmod +x /docker-entrypoint.sh +ENV BACKEND_URL=http://localhost:8181 EXPOSE 5173 - -# Start Vite dev server with host binding for Docker -CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"] +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/archon-ui-main/azure.env b/archon-ui-main/azure.env new file mode 100644 index 0000000000..e1c56fbb60 --- /dev/null +++ b/archon-ui-main/azure.env @@ -0,0 +1,17 @@ +# Azure Container Apps Environment Configuration +# This file contains environment variables for Azure deployment + +# Backend API URL (Archon Server) +VITE_API_URL=https://archon-server.purplemoss-0b16bcfe.eastus.azurecontainerapps.io + +# MCP Server URL (Archon MCP) +VITE_MCP_SERVER_URL=https://archon-mcp.purplemoss-0b16bcfe.eastus.azurecontainerapps.io + +# Agents Service URL (Archon Agents) +VITE_AGENTS_URL=https://archon-agents.purplemoss-0b16bcfe.eastus.azurecontainerapps.io + +# Environment indicator +VITE_DEPLOYMENT_ENV=azure + + + diff --git a/archon-ui-main/entrypoint.sh b/archon-ui-main/entrypoint.sh new file mode 100644 index 0000000000..a158b5c50a --- /dev/null +++ b/archon-ui-main/entrypoint.sh @@ -0,0 +1,16 @@ +#!/bin/sh +set -e + +if [ -n "$BACKEND_URL" ]; then + export BACKEND_HOST=$(echo $BACKEND_URL | sed 's|https\?://||' | cut -d'/' -f1) +else + export BACKEND_HOST="localhost" +fi + +echo "Backend URL: $BACKEND_URL" +echo "Backend Host: $BACKEND_HOST" + +envsubst '${BACKEND_URL} ${BACKEND_HOST}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf +rm /etc/nginx/conf.d/default.conf.template + +exec "$@" \ No newline at end of file diff --git a/archon-ui-main/nginx.conf.template b/archon-ui-main/nginx.conf.template new file mode 100644 index 0000000000..2dbd7fd08d --- /dev/null +++ b/archon-ui-main/nginx.conf.template @@ -0,0 +1,64 @@ +server { + listen 5173; + server_name _; + + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $uri $uri/ /index.html; + + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + } + + location /api/ { + proxy_pass ${BACKEND_URL}/api/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host ${BACKEND_HOST}; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + proxy_ssl_verify off; + proxy_ssl_server_name on; + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + location /health { + proxy_pass ${BACKEND_URL}/health; + proxy_http_version 1.1; + proxy_set_header Host ${BACKEND_HOST}; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_ssl_verify off; + proxy_ssl_server_name on; + } + + location /socket.io/ { + proxy_pass ${BACKEND_URL}/socket.io/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host ${BACKEND_HOST}; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_ssl_verify off; + proxy_ssl_server_name on; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } +} \ No newline at end of file diff --git a/archon-ui-main/src/components/project-tasks/DocsTab.tsx b/archon-ui-main/src/components/project-tasks/DocsTab.tsx index 87e6fa5c65..cd18f303a0 100644 --- a/archon-ui-main/src/components/project-tasks/DocsTab.tsx +++ b/archon-ui-main/src/components/project-tasks/DocsTab.tsx @@ -509,6 +509,7 @@ export const DocsTab = ({ title: string; created_at?: string; updated_at?: string; + docs?: any[]; // Add docs field to match Project interface } | null; }) => { // Document state @@ -560,11 +561,22 @@ export const DocsTab = ({ // Load project documents from the project data const loadProjectDocuments = async () => { - if (!project?.id || !project.docs) return; + if (!project?.id) { + console.log('DocsTab: No project ID available'); + return; + } try { setLoading(true); + // Check if project has docs field + if (!project.docs) { + console.log('DocsTab: Project has no docs field, documents array will be empty'); + setDocuments([]); + setSelectedDocument(null); + return; + } + // Use the docs directly from the project data const projectDocuments: ProjectDoc[] = project.docs.map((doc: any) => ({ id: doc.id, @@ -582,10 +594,12 @@ export const DocsTab = ({ setSelectedDocument(projectDocuments[0]); } - console.log(`Loaded ${projectDocuments.length} documents from project data`); + console.log(`DocsTab: Loaded ${projectDocuments.length} documents from project data:`, projectDocuments); } catch (error) { - console.error('Failed to load documents:', error); + console.error('DocsTab: Failed to load documents:', error); showToast('Failed to load documents', 'error'); + setDocuments([]); + setSelectedDocument(null); } finally { setLoading(false); } diff --git a/archon-ui-main/src/components/smart-crawling/SmartCrawlConfig.tsx b/archon-ui-main/src/components/smart-crawling/SmartCrawlConfig.tsx new file mode 100644 index 0000000000..c9bc7cd754 --- /dev/null +++ b/archon-ui-main/src/components/smart-crawling/SmartCrawlConfig.tsx @@ -0,0 +1,494 @@ +/** + * Smart Crawling Mode Configuration Components + * + * Provides UI components for configuring and managing different crawling modes + * including e-commerce, blog, documentation, and analytics modes. + */ + +import React, { useState, useEffect } from 'react'; +import { + Settings, + ShoppingCart, + FileText, + BookOpen, + BarChart3, + Globe, + Save, + RotateCcw, + AlertTriangle, + CheckCircle, + Loader2 +} from 'lucide-react'; + +// Types +interface CrawlModeConfig { + mode_name: string; + enabled: boolean; + priority: string; + max_pages: number; + max_depth: number; + concurrent_requests: number; + delay_between_requests: number; + custom_settings: Record; +} + +interface CrawlMode { + name: string; + enabled: boolean; + description: string; + supported_websites: string[]; + configuration: CrawlModeConfig; +} + +// Main configuration panel +export const SmartCrawlConfigPanel: React.FC = () => { + const [modes, setModes] = useState([]); + const [loading, setLoading] = useState(true); + const [selectedMode, setSelectedMode] = useState(null); + const [saving, setSaving] = useState(false); + + useEffect(() => { + loadCrawlingModes(); + }, []); + + const loadCrawlingModes = async () => { + try { + const response = await fetch('/api/smart-crawl/modes'); + const data = await response.json(); + if (data.success) { + setModes(data.modes); + } + } catch (error) { + console.error('Failed to load crawling modes:', error); + } finally { + setLoading(false); + } + }; + + const handleModeUpdate = async (modeName: string, config: CrawlModeConfig) => { + setSaving(true); + try { + const response = await fetch(`/api/smart-crawl/modes/${modeName}/config`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(config) + }); + + if (response.ok) { + await loadCrawlingModes(); // Refresh data + } + } catch (error) { + console.error('Failed to update mode:', error); + } finally { + setSaving(false); + } + }; + + if (loading) { + return ( +
+ + Loading crawling modes... +
+ ); + } + + return ( +
+
+

+ + Smart Crawling Configuration +

+
+ +
+ {/* Mode Selection */} +
+

Crawling Modes

+
+ {modes.map((mode) => ( + setSelectedMode(mode.name)} + /> + ))} +
+
+ + {/* Configuration Panel */} +
+ {selectedMode ? ( + m.name === selectedMode)!} + onUpdate={handleModeUpdate} + saving={saving} + /> + ) : ( +
+ +

Select a crawling mode to configure

+
+ )} +
+
+
+ ); +}; + +// Individual mode card +const ModeCard: React.FC<{ + mode: CrawlMode; + isSelected: boolean; + onSelect: () => void; +}> = ({ mode, isSelected, onSelect }) => { + const getModeIcon = (modeName: string) => { + switch (modeName) { + case 'ecommerce': return ; + case 'blog': return ; + case 'documentation': return ; + case 'analytics': return ; + default: return ; + } + }; + + return ( +
+
+
+ {getModeIcon(mode.name)} +
+ +
+
+

{mode.name}

+ {mode.enabled ? ( + + ) : ( + + )} +
+ +

{mode.description}

+ +
+ Supports: {mode.supported_websites.slice(0, 2).join(', ')} + {mode.supported_websites.length > 2 && '...'} +
+
+
+
+ ); +}; + +// Mode configuration editor +const ModeConfigEditor: React.FC<{ + mode: CrawlMode; + onUpdate: (modeName: string, config: CrawlModeConfig) => void; + saving: boolean; +}> = ({ mode, onUpdate, saving }) => { + const [config, setConfig] = useState(mode.configuration); + const [hasChanges, setHasChanges] = useState(false); + + useEffect(() => { + setConfig(mode.configuration); + setHasChanges(false); + }, [mode]); + + const handleConfigChange = (field: keyof CrawlModeConfig, value: any) => { + setConfig(prev => ({ ...prev, [field]: value })); + setHasChanges(true); + }; + + const handleCustomSettingChange = (key: string, value: any) => { + setConfig(prev => ({ + ...prev, + custom_settings: { ...prev.custom_settings, [key]: value } + })); + setHasChanges(true); + }; + + const handleSave = () => { + onUpdate(mode.name, config); + setHasChanges(false); + }; + + const handleReset = () => { + setConfig(mode.configuration); + setHasChanges(false); + }; + + return ( +
+
+

+ {mode.name} Configuration +

+ +
+ {hasChanges && ( + + )} + + +
+
+ + {/* Basic Configuration */} +
+
+ + +
+ +
+ + +
+ +
+ + handleConfigChange('max_pages', parseInt(e.target.value))} + className="w-full px-3 py-2 border rounded-md" + /> +
+ +
+ + handleConfigChange('max_depth', parseInt(e.target.value))} + className="w-full px-3 py-2 border rounded-md" + /> +
+ +
+ + handleConfigChange('concurrent_requests', parseInt(e.target.value))} + className="w-full px-3 py-2 border rounded-md" + /> +
+ +
+ + handleConfigChange('delay_between_requests', parseFloat(e.target.value))} + className="w-full px-3 py-2 border rounded-md" + /> +
+
+ + {/* Mode-specific Configuration */} + +
+ ); +}; + +// Mode-specific configuration sections +const ModeSpecificConfig: React.FC<{ + modeName: string; + customSettings: Record; + onChange: (key: string, value: any) => void; +}> = ({ modeName, customSettings, onChange }) => { + if (modeName === 'ecommerce') { + return ( +
+

E-commerce Specific Settings

+
+
+ onChange('extract_variants', e.target.checked)} + /> + +
+ +
+ onChange('extract_reviews', e.target.checked)} + /> + +
+ +
+ onChange('track_price_changes', e.target.checked)} + /> + +
+ +
+ + onChange('max_images_per_product', parseInt(e.target.value))} + className="w-full px-3 py-2 border rounded-md" + /> +
+
+
+ ); + } + + if (modeName === 'blog') { + return ( +
+

Blog Specific Settings

+
+
+ onChange('extract_author', e.target.checked)} + /> + +
+ +
+ onChange('extract_tags', e.target.checked)} + /> + +
+ +
+ + onChange('min_article_length', parseInt(e.target.value))} + className="w-full px-3 py-2 border rounded-md" + /> +
+
+
+ ); + } + + if (modeName === 'documentation') { + return ( +
+

Documentation Specific Settings

+
+
+ onChange('extract_code_examples', e.target.checked)} + /> + +
+ +
+ onChange('extract_api_endpoints', e.target.checked)} + /> + +
+ +
+ onChange('follow_internal_links', e.target.checked)} + /> + +
+
+
+ ); + } + + return null; +}; \ No newline at end of file diff --git a/archon-ui-main/src/pages/ProjectPage.tsx b/archon-ui-main/src/pages/ProjectPage.tsx index aebb92dad5..689b210013 100644 --- a/archon-ui-main/src/pages/ProjectPage.tsx +++ b/archon-ui-main/src/pages/ProjectPage.tsx @@ -389,11 +389,36 @@ export function ProjectPage({ } }; - const handleProjectSelect = (project: Project) => { - setSelectedProject(project); - setShowProjectDetails(true); - setActiveTab('tasks'); // Default to tasks tab when a new project is selected - loadTasksForProject(project.id); // Load tasks for the selected project + const handleProjectSelect = async (project: Project) => { + try { + // Fetch the complete project data including docs, features, and data + const fullProject = await projectService.getProject(project.id); + setSelectedProject(fullProject); + setShowProjectDetails(true); + setActiveTab('tasks'); // Default to tasks tab when a new project is selected + loadTasksForProject(project.id); // Load tasks for the selected project + } catch (error) { + console.error('Failed to load full project data:', error); + // Fallback to basic project data if fetch fails + setSelectedProject(project); + setShowProjectDetails(true); + setActiveTab('tasks'); + loadTasksForProject(project.id); + } + }; + + // Refresh project data when switching to docs tab + const handleTabChange = async (newTab: string) => { + if (newTab === 'docs' && selectedProject) { + try { + // Refresh project data to ensure latest docs are available + const refreshedProject = await projectService.getProject(selectedProject.id); + setSelectedProject(refreshedProject); + } catch (error) { + console.error('Failed to refresh project data for docs tab:', error); + } + } + setActiveTab(newTab); }; const handleDeleteProject = useCallback(async (e: React.MouseEvent, projectId: string, projectTitle: string) => { @@ -473,10 +498,21 @@ export function ProjectPage({ // If pinning a project, also select it if (newPinnedState) { console.log(`[PIN] Selecting newly pinned project: ${project.title}`); - setSelectedProject({ ...project, pinned: true }); - setShowProjectDetails(true); - setActiveTab('tasks'); // Default to tasks tab - loadTasksForProject(project.id); + try { + // Fetch the complete project data including docs, features, and data + const fullProject = await projectService.getProject(project.id); + setSelectedProject({ ...fullProject, pinned: true }); + setShowProjectDetails(true); + setActiveTab('tasks'); // Default to tasks tab + loadTasksForProject(project.id); + } catch (error) { + console.error('Failed to load full project data for pinned project:', error); + // Fallback to basic project data if fetch fails + setSelectedProject({ ...project, pinned: true }); + setShowProjectDetails(true); + setActiveTab('tasks'); + loadTasksForProject(project.id); + } } else if (selectedProject?.id === project.id) { // If unpinning the currently selected project, just update its pin state console.log(`[PIN] Updating selected project's pin state`); @@ -885,7 +921,7 @@ export function ProjectPage({ {/* Project Details Section */} {showProjectDetails && selectedProject && ( - + Docs diff --git a/archon-ui-main/src/services/mcpClientService.ts b/archon-ui-main/src/services/mcpClientService.ts index 2010c9bfec..0ac6d3e7e9 100644 --- a/archon-ui-main/src/services/mcpClientService.ts +++ b/archon-ui-main/src/services/mcpClientService.ts @@ -398,13 +398,33 @@ class MCPClientService { * Create Archon MCP client using Streamable HTTP transport */ async createArchonClient(): Promise { - // Require ARCHON_MCP_PORT to be set + // Check for Azure Container Apps MCP server URL first + const mcpServerUrl = import.meta.env.VITE_MCP_SERVER_URL; + if (mcpServerUrl) { + // Use the Azure Container App MCP server URL + const mcpUrl = `${mcpServerUrl}/mcp`; + + const archonConfig: MCPClientConfig = { + name: 'Archon', + transport_type: 'http', + connection_config: { + url: mcpUrl + }, + auto_connect: true, + health_check_interval: 30, + is_default: true + }; + + return this.createClient(archonConfig); + } + + // Fallback to local development (require ARCHON_MCP_PORT to be set) const mcpPort = import.meta.env.ARCHON_MCP_PORT; if (!mcpPort) { throw new Error( - 'ARCHON_MCP_PORT environment variable is required. ' + - 'Please set it in your environment variables. ' + - 'Default value: 8051' + 'Neither VITE_MCP_SERVER_URL nor ARCHON_MCP_PORT environment variables are set. ' + + 'Please set VITE_MCP_SERVER_URL for Azure Container Apps or ARCHON_MCP_PORT for local development. ' + + 'Default values: VITE_MCP_SERVER_URL=https://archon-mcp.purplemoss-0b16bcfe.eastus.azurecontainerapps.io or ARCHON_MCP_PORT=8051' ); } diff --git a/archon-ui-main/src/services/projectService.ts b/archon-ui-main/src/services/projectService.ts index 50e8f56585..d3a5bcc348 100644 --- a/archon-ui-main/src/services/projectService.ts +++ b/archon-ui-main/src/services/projectService.ts @@ -663,7 +663,8 @@ export const projectService = { async restoreDocumentVersion(projectId: string, versionNumber: number, fieldName: string = 'docs'): Promise { try { const response = await callAPI(`/api/projects/${projectId}/versions/${fieldName}/${versionNumber}/restore`, { - method: 'POST' + method: 'POST', + body: JSON.stringify({ restored_by: 'user' }) }); // Broadcast restore event diff --git a/archon-ui-main/vite.config.js b/archon-ui-main/vite.config.js new file mode 100644 index 0000000000..869510f37a --- /dev/null +++ b/archon-ui-main/vite.config.js @@ -0,0 +1,20 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], + server: { + host: '0.0.0.0', + port: 5173, + allowedHosts: 'all' + }, + preview: { + host: '0.0.0.0', + port: 5173, + allowedHosts: 'all' + }, + build: { + outDir: 'dist', + sourcemap: false + } +}) diff --git a/archon-ui-main/vite.config.ts b/archon-ui-main/vite.config.ts index 0c812614b5..a80a2035ad 100644 --- a/archon-ui-main/vite.config.ts +++ b/archon-ui-main/vite.config.ts @@ -12,14 +12,21 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => { // Load environment variables const env = loadEnv(mode, process.cwd(), ''); - // Get host and port from environment variables or use defaults - // For internal Docker communication, use the service name - // For external access, use the HOST from environment - const isDocker = process.env.DOCKER_ENV === 'true' || !!process.env.HOSTNAME; - const internalHost = 'archon-server'; // Docker service name for internal communication - const externalHost = process.env.HOST || 'localhost'; // Host for external access - const host = isDocker ? internalHost : externalHost; - const port = process.env.ARCHON_SERVER_PORT || env.ARCHON_SERVER_PORT || '8181'; + // Azure Container Apps configuration + // Use environment variables for backend URL, with fallbacks + const backendUrl = env.VITE_API_URL || + process.env.VITE_API_URL || + 'http://localhost:8181'; + + // MCP Server URL for Azure Container Apps + const mcpServerUrl = env.VITE_MCP_SERVER_URL || + process.env.VITE_MCP_SERVER_URL || + 'https://archon-mcp.purplemoss-0b16bcfe.eastus.azurecontainerapps.io'; + + console.log('[VITE CONFIG] Backend URL:', backendUrl); + console.log('[VITE CONFIG] MCP Server URL:', mcpServerUrl); + console.log('[VITE CONFIG] Using environment variable VITE_API_URL:', env.VITE_API_URL); + console.log('[VITE CONFIG] Using environment variable VITE_MCP_SERVER_URL:', env.VITE_MCP_SERVER_URL); return { plugins: [ @@ -282,32 +289,56 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => { strictPort: true, // Exit if port is in use proxy: { '/api': { - target: `http://${host}:${port}`, + target: backendUrl, changeOrigin: true, - secure: false, + secure: true, // Use true for HTTPS backends ws: true, configure: (proxy, options) => { proxy.on('error', (err, req, res) => { - console.log('🚨 [VITE PROXY ERROR]:', err.message); - console.log('🚨 [VITE PROXY ERROR] Target:', `http://${host}:${port}`); - console.log('🚨 [VITE PROXY ERROR] Request:', req.url); + console.log('VITE PROXY ERROR:', err.message); + console.log('VITE PROXY ERROR Target:', backendUrl); + console.log('VITE PROXY ERROR Request:', req.url); }); proxy.on('proxyReq', (proxyReq, req, res) => { - console.log('🔄 [VITE PROXY] Forwarding:', req.method, req.url, 'to', `http://${host}:${port}${req.url}`); + console.log('VITE PROXY Forwarding:', req.method, req.url, 'to', `${backendUrl}${req.url}`); }); } }, // Socket.IO specific proxy configuration '/socket.io': { - target: `http://${host}:${port}`, + target: backendUrl, changeOrigin: true, + secure: true, ws: true + }, + // Health check proxy + '/health': { + target: backendUrl, + changeOrigin: true, + secure: true + }, + // MCP Server proxy for Azure Container Apps + '/mcp': { + target: mcpServerUrl, + changeOrigin: true, + secure: true, + ws: true, + configure: (proxy, options) => { + proxy.on('error', (err, req, res) => { + console.log('VITE MCP PROXY ERROR:', err.message); + console.log('VITE MCP PROXY ERROR Target:', mcpServerUrl); + console.log('VITE MCP PROXY ERROR Request:', req.url); + }); + proxy.on('proxyReq', (proxyReq, req, res) => { + console.log('VITE MCP PROXY Forwarding:', req.method, req.url, 'to', `${mcpServerUrl}${req.url}`); + }); + } } }, }, define: { - 'import.meta.env.VITE_HOST': JSON.stringify(host), - 'import.meta.env.VITE_PORT': JSON.stringify(port), + 'import.meta.env.VITE_BACKEND_URL': JSON.stringify(backendUrl), + 'import.meta.env.VITE_MCP_SERVER_URL': JSON.stringify(mcpServerUrl), }, resolve: { alias: { @@ -328,8 +359,7 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => { '**/*.test.{ts,tsx}', ], env: { - VITE_HOST: host, - VITE_PORT: port, + VITE_BACKEND_URL: backendUrl, }, coverage: { provider: 'v8', @@ -345,4 +375,4 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => { } } }; -}); +}); \ No newline at end of file diff --git a/coleam00-archon-8a5edab282632443.txt b/coleam00-archon-8a5edab282632443.txt new file mode 100644 index 0000000000..989998d575 --- /dev/null +++ b/coleam00-archon-8a5edab282632443.txt @@ -0,0 +1,123473 @@ +Directory structure: +└── coleam00-archon/ + ├── README.md + ├── CLAUDE.md + ├── CONTRIBUTING.md + ├── docker-compose.docs.yml + ├── docker-compose.yml + ├── LICENSE + ├── .dockerignore + ├── .env.example + ├── archon-ui-main/ + │ ├── README.md + │ ├── Dockerfile + │ ├── index.html + │ ├── package.json + │ ├── postcss.config.js + │ ├── tailwind.config.js + │ ├── tsconfig.json + │ ├── tsconfig.node.json + │ ├── vite.config.ts + │ ├── vitest.config.ts + │ ├── .dockerignore + │ ├── .eslintrc.cjs + │ ├── __mocks__/ + │ │ └── lucide-react.tsx + │ ├── docs/ + │ │ └── socket-memoization-patterns.md + │ ├── src/ + │ │ ├── App.tsx + │ │ ├── env.d.ts + │ │ ├── index.css + │ │ ├── index.tsx + │ │ ├── components/ + │ │ │ ├── BackendStartupError.tsx + │ │ │ ├── DisconnectScreenOverlay.tsx + │ │ │ ├── ProjectCreationProgressCard.tsx + │ │ │ ├── animations/ + │ │ │ │ ├── Animations.tsx + │ │ │ │ └── DisconnectScreenAnimations.tsx + │ │ │ ├── bug-report/ + │ │ │ │ ├── BugReportButton.tsx + │ │ │ │ ├── BugReportModal.tsx + │ │ │ │ └── ErrorBoundaryWithBugReport.tsx + │ │ │ ├── code/ + │ │ │ │ └── CodeViewerModal.tsx + │ │ │ ├── knowledge-base/ + │ │ │ │ ├── CrawlingProgressCard.tsx + │ │ │ │ ├── EditKnowledgeItemModal.tsx + │ │ │ │ ├── GroupCreationModal.tsx + │ │ │ │ ├── GroupedKnowledgeItemCard.tsx + │ │ │ │ ├── KnowledgeItemCard.tsx + │ │ │ │ ├── KnowledgeItemSkeleton.tsx + │ │ │ │ └── KnowledgeTable.tsx + │ │ │ ├── layouts/ + │ │ │ │ ├── ArchonChatPanel.tsx + │ │ │ │ ├── MainLayout.tsx + │ │ │ │ └── SideNavigation.tsx + │ │ │ ├── mcp/ + │ │ │ │ ├── ClientCard.tsx + │ │ │ │ ├── MCPClients.tsx + │ │ │ │ └── ToolTestingPanel.tsx + │ │ │ ├── onboarding/ + │ │ │ │ └── ProviderStep.tsx + │ │ │ ├── project-tasks/ + │ │ │ │ ├── DataTab.tsx + │ │ │ │ ├── DocumentCard.tsx + │ │ │ │ ├── DraggableTaskCard.tsx + │ │ │ │ ├── EditTaskModal.tsx + │ │ │ │ ├── FeaturesTab.tsx + │ │ │ │ ├── MilkdownEditor.css + │ │ │ │ ├── MilkdownEditor.tsx + │ │ │ │ ├── Tabs.tsx + │ │ │ │ ├── TaskBoardView.tsx + │ │ │ │ ├── TaskInputComponents.tsx + │ │ │ │ ├── TasksTab.tsx + │ │ │ │ ├── TaskTableView.tsx + │ │ │ │ └── VersionHistoryModal.tsx + │ │ │ ├── prp/ + │ │ │ │ ├── index.ts + │ │ │ │ ├── PRPViewer.css + │ │ │ │ ├── PRPViewer.tsx + │ │ │ │ ├── components/ + │ │ │ │ │ ├── CollapsibleSectionRenderer.tsx + │ │ │ │ │ ├── CollapsibleSectionWrapper.tsx + │ │ │ │ │ ├── MarkdownDocumentRenderer.tsx + │ │ │ │ │ ├── MarkdownSectionRenderer.tsx + │ │ │ │ │ └── SimpleMarkdown.tsx + │ │ │ │ ├── renderers/ + │ │ │ │ │ └── SectionRenderer.tsx + │ │ │ │ ├── sections/ + │ │ │ │ │ ├── ContextSection.tsx + │ │ │ │ │ ├── FeatureSection.tsx + │ │ │ │ │ ├── FlowSection.tsx + │ │ │ │ │ ├── GenericSection.tsx + │ │ │ │ │ ├── KeyValueSection.tsx + │ │ │ │ │ ├── ListSection.tsx + │ │ │ │ │ ├── MetadataSection.tsx + │ │ │ │ │ ├── MetricsSection.tsx + │ │ │ │ │ ├── ObjectSection.tsx + │ │ │ │ │ ├── PersonaSection.tsx + │ │ │ │ │ ├── PlanSection.tsx + │ │ │ │ │ ├── RolloutPlanSection.tsx + │ │ │ │ │ └── TokenSystemSection.tsx + │ │ │ │ ├── types/ + │ │ │ │ │ └── prp.types.ts + │ │ │ │ └── utils/ + │ │ │ │ ├── formatters.ts + │ │ │ │ ├── markdownParser.ts + │ │ │ │ ├── normalizer.ts + │ │ │ │ ├── objectRenderer.tsx + │ │ │ │ └── sectionDetector.ts + │ │ │ ├── settings/ + │ │ │ │ ├── APIKeysSection.tsx + │ │ │ │ ├── ButtonPlayground.tsx + │ │ │ │ ├── CodeExtractionSettings.tsx + │ │ │ │ ├── FeaturesSection.tsx + │ │ │ │ ├── IDEGlobalRules.tsx + │ │ │ │ ├── RAGSettings.tsx + │ │ │ │ ├── TestStatus.tsx + │ │ │ │ └── TestStatus.tsx.backup + │ │ │ └── ui/ + │ │ │ ├── Badge.tsx + │ │ │ ├── Button.tsx + │ │ │ ├── Card.tsx + │ │ │ ├── Checkbox.tsx + │ │ │ ├── CollapsibleSettingsCard.tsx + │ │ │ ├── CoverageBar.tsx + │ │ │ ├── CoverageModal.tsx + │ │ │ ├── CoverageVisualization.tsx + │ │ │ ├── GlassCrawlDepthSelector.tsx + │ │ │ ├── Input.tsx + │ │ │ ├── NeonButton.tsx + │ │ │ ├── PowerButton.tsx + │ │ │ ├── Select.tsx + │ │ │ ├── TestResultDashboard.tsx + │ │ │ ├── TestResultsModal.tsx + │ │ │ ├── ThemeToggle.tsx + │ │ │ └── Toggle.tsx + │ │ ├── config/ + │ │ │ └── api.ts + │ │ ├── contexts/ + │ │ │ ├── SettingsContext.tsx + │ │ │ ├── ThemeContext.tsx + │ │ │ └── ToastContext.tsx + │ │ ├── hooks/ + │ │ │ ├── useBugReport.ts + │ │ │ ├── useCardTilt.ts + │ │ │ ├── useNeonGlow.ts + │ │ │ ├── useOptimisticUpdates.ts + │ │ │ ├── useSocketSubscription.ts + │ │ │ ├── useStaggeredEntrance.ts + │ │ │ ├── useTaskSocket.ts + │ │ │ └── useTerminalScroll.ts + │ │ ├── lib/ + │ │ │ ├── projectSchemas.ts + │ │ │ ├── task-utils.tsx + │ │ │ └── utils.ts + │ │ ├── pages/ + │ │ │ ├── MCPPage.tsx + │ │ │ ├── OnboardingPage.tsx + │ │ │ └── SettingsPage.tsx + │ │ ├── services/ + │ │ │ ├── agentChatService.ts + │ │ │ ├── api.ts + │ │ │ ├── bugReportService.ts + │ │ │ ├── crawlProgressService.ts + │ │ │ ├── credentialsService.ts + │ │ │ ├── knowledgeBaseService.ts + │ │ │ ├── mcpClientService.ts + │ │ │ ├── mcpServerService.ts + │ │ │ ├── mcpService.ts + │ │ │ ├── projectCreationProgressService.ts + │ │ │ ├── projectService.ts + │ │ │ ├── serverHealthService.ts + │ │ │ ├── socketIOService.ts + │ │ │ ├── socketService.ts + │ │ │ ├── taskSocketService.ts + │ │ │ └── testService.ts + │ │ ├── styles/ + │ │ │ ├── card-animations.css + │ │ │ ├── luminous-button.css + │ │ │ └── toggle.css + │ │ ├── types/ + │ │ │ ├── knowledge.ts + │ │ │ └── project.ts + │ │ └── utils/ + │ │ └── onboarding.ts + │ └── test/ + │ ├── components.test.tsx + │ ├── errors.test.tsx + │ ├── pages.test.tsx + │ ├── setup.ts + │ ├── user_flows.test.tsx + │ ├── components/ + │ │ ├── project-tasks/ + │ │ │ ├── DocsTab.integration.test.tsx + │ │ │ ├── DocumentCard.test.tsx + │ │ │ └── MilkdownEditor.test.tsx + │ │ └── prp/ + │ │ └── PRPViewer.test.tsx + │ ├── config/ + │ │ └── api.test.ts + │ └── services/ + │ └── projectService.test.ts + ├── docs/ + │ ├── README.md + │ ├── babel.config.js + │ ├── Dockerfile + │ ├── docusaurus.config.js + │ ├── package.json + │ ├── sidebars.js + │ ├── docs/ + │ │ ├── README.md + │ │ ├── agent-chat.mdx + │ │ ├── agent-document.mdx + │ │ ├── agent-rag.mdx + │ │ ├── agent-task.mdx + │ │ ├── agents-overview.mdx + │ │ ├── api-reference.mdx + │ │ ├── architecture.mdx + │ │ ├── background-tasks.mdx + │ │ ├── code-extraction-rules.mdx + │ │ ├── coding-best-practices.mdx + │ │ ├── configuration.mdx + │ │ ├── crawling-configuration.mdx + │ │ ├── deployment.mdx + │ │ ├── getting-started.mdx + │ │ ├── intro.mdx + │ │ ├── knowledge-features.mdx + │ │ ├── knowledge-overview.mdx + │ │ ├── mcp-overview.mdx + │ │ ├── mcp-server.mdx + │ │ ├── mcp-tools.mdx + │ │ ├── projects-features.mdx + │ │ ├── projects-overview.mdx + │ │ ├── rag.mdx + │ │ ├── server-deployment.mdx + │ │ ├── server-monitoring.mdx + │ │ ├── server-overview.mdx + │ │ ├── server-services.mdx + │ │ ├── socketio.mdx + │ │ ├── testing-python-strategy.mdx + │ │ ├── testing-vitest-strategy.mdx + │ │ ├── testing.mdx + │ │ ├── ui-components.mdx + │ │ └── ui.mdx + │ ├── src/ + │ │ ├── css/ + │ │ │ └── custom.css + │ │ └── pages/ + │ │ ├── index.js + │ │ ├── index.module.css + │ │ └── markdown-page.md + │ └── static/ + │ ├── .nojekyll + │ └── js/ + │ └── mermaid-rounded-corners.js + ├── migration/ + │ ├── complete_setup.sql + │ └── RESET_DB.sql + ├── original_archon/ + │ ├── README.md + │ ├── Dockerfile + │ ├── graph_service.py + │ ├── LICENSE + │ ├── requirements.txt + │ ├── run_docker.py + │ ├── streamlit_ui.py + │ ├── .dockerignore + │ ├── .env.example + │ ├── agent-resources/ + │ │ ├── examples/ + │ │ │ ├── pydantic_github_agent.py + │ │ │ ├── pydantic_mcp_agent.py + │ │ │ └── pydantic_web_search_agent.py + │ │ ├── mcps/ + │ │ │ ├── airtable.json + │ │ │ ├── brave_search.json + │ │ │ ├── chroma.json + │ │ │ ├── file_system.json + │ │ │ ├── firecrawl.json + │ │ │ ├── git.json + │ │ │ ├── github.json + │ │ │ ├── google_drive.json + │ │ │ ├── qdrant.json + │ │ │ ├── redis.json + │ │ │ ├── slack.json + │ │ │ └── sqlite.json + │ │ └── tools/ + │ │ ├── get_github_file.py + │ │ ├── get_github_file_structure.py + │ │ ├── get_github_repo_info.py + │ │ └── web_search.py + │ ├── archon/ + │ │ ├── __init__.py + │ │ ├── advisor_agent.py + │ │ ├── agent_prompts.py + │ │ ├── agent_tools.py + │ │ ├── archon_graph.py + │ │ ├── crawl_pydantic_ai_docs.py + │ │ ├── langgraph.json + │ │ ├── pydantic_ai_coder.py + │ │ └── refiner_agents/ + │ │ ├── agent_refiner_agent.py + │ │ ├── prompt_refiner_agent.py + │ │ └── tools_refiner_agent.py + │ ├── iterations/ + │ │ ├── v1-single-agent/ + │ │ │ ├── README.md + │ │ │ ├── crawl_pydantic_ai_docs.py + │ │ │ ├── pydantic_ai_coder.py + │ │ │ ├── requirements.txt + │ │ │ ├── site_pages.sql + │ │ │ ├── streamlit_ui.py + │ │ │ └── .env.example + │ │ ├── v2-agentic-workflow/ + │ │ │ ├── README.md + │ │ │ ├── archon_graph.py + │ │ │ ├── crawl_pydantic_ai_docs.py + │ │ │ ├── langgraph.json + │ │ │ ├── ollama_site_pages.sql + │ │ │ ├── pydantic_ai_coder.py + │ │ │ ├── requirements.txt + │ │ │ ├── site_pages.sql + │ │ │ ├── streamlit_ui.py + │ │ │ └── .env.example + │ │ ├── v3-mcp-support/ + │ │ │ ├── README.md + │ │ │ ├── graph_service.py + │ │ │ ├── mcp-config.json + │ │ │ ├── mcp_server.py + │ │ │ ├── requirements.txt + │ │ │ ├── setup_mcp.py + │ │ │ ├── streamlit_ui.py + │ │ │ ├── .env.example + │ │ │ ├── archon/ + │ │ │ │ ├── __init__.py + │ │ │ │ ├── archon_graph.py + │ │ │ │ ├── crawl_pydantic_ai_docs.py + │ │ │ │ ├── langgraph.json + │ │ │ │ └── pydantic_ai_coder.py + │ │ │ └── utils/ + │ │ │ ├── ollama_site_pages.sql + │ │ │ ├── site_pages.sql + │ │ │ └── utils.py + │ │ ├── v4-streamlit-ui-overhaul/ + │ │ │ ├── README.md + │ │ │ ├── Dockerfile + │ │ │ ├── future_enhancements.py + │ │ │ ├── graph_service.py + │ │ │ ├── mcp_server.py + │ │ │ ├── requirements.txt + │ │ │ ├── run_docker.py + │ │ │ ├── .dockerignore + │ │ │ ├── .env.example + │ │ │ ├── archon/ + │ │ │ │ ├── __init__.py + │ │ │ │ ├── archon_graph.py + │ │ │ │ ├── crawl_pydantic_ai_docs.py + │ │ │ │ ├── langgraph.json + │ │ │ │ └── pydantic_ai_coder.py + │ │ │ ├── mcp/ + │ │ │ │ ├── Dockerfile + │ │ │ │ ├── mcp_server.py + │ │ │ │ ├── requirements.txt + │ │ │ │ └── .dockerignore + │ │ │ ├── utils/ + │ │ │ │ ├── site_pages.sql + │ │ │ │ └── utils.py + │ │ │ └── .streamlit/ + │ │ │ └── config.toml + │ │ ├── v5-parallel-specialized-agents/ + │ │ │ ├── README.md + │ │ │ ├── Dockerfile + │ │ │ ├── graph_service.py + │ │ │ ├── requirements.txt + │ │ │ ├── run_docker.py + │ │ │ ├── streamlit_ui.py + │ │ │ ├── .dockerignore + │ │ │ ├── .env.example + │ │ │ ├── archon/ + │ │ │ │ ├── __init__.py + │ │ │ │ ├── agent_prompts.py + │ │ │ │ ├── agent_tools.py + │ │ │ │ ├── archon_graph.py + │ │ │ │ ├── crawl_pydantic_ai_docs.py + │ │ │ │ ├── langgraph.json + │ │ │ │ ├── pydantic_ai_coder.py + │ │ │ │ └── refiner_agents/ + │ │ │ │ ├── agent_refiner_agent.py + │ │ │ │ ├── prompt_refiner_agent.py + │ │ │ │ └── tools_refiner_agent.py + │ │ │ ├── mcp/ + │ │ │ │ ├── Dockerfile + │ │ │ │ ├── mcp_server.py + │ │ │ │ ├── requirements.txt + │ │ │ │ └── .dockerignore + │ │ │ ├── streamlit_pages/ + │ │ │ │ ├── __init__.py + │ │ │ │ ├── agent_service.py + │ │ │ │ ├── chat.py + │ │ │ │ ├── database.py + │ │ │ │ ├── documentation.py + │ │ │ │ ├── environment.py + │ │ │ │ ├── future_enhancements.py + │ │ │ │ ├── intro.py + │ │ │ │ ├── mcp.py + │ │ │ │ └── styles.py + │ │ │ └── utils/ + │ │ │ ├── site_pages.sql + │ │ │ └── utils.py + │ │ └── v6-tool-library-integration/ + │ │ ├── README.md + │ │ ├── Dockerfile + │ │ ├── graph_service.py + │ │ ├── requirements.txt + │ │ ├── run_docker.py + │ │ ├── streamlit_ui.py + │ │ ├── .dockerignore + │ │ ├── .env.example + │ │ ├── agent-resources/ + │ │ │ ├── examples/ + │ │ │ │ ├── pydantic_github_agent.py + │ │ │ │ ├── pydantic_mcp_agent.py + │ │ │ │ └── pydantic_web_search_agent.py + │ │ │ ├── mcps/ + │ │ │ │ ├── airtable.json + │ │ │ │ ├── brave_search.json + │ │ │ │ ├── chroma.json + │ │ │ │ ├── file_system.json + │ │ │ │ ├── firecrawl.json + │ │ │ │ ├── git.json + │ │ │ │ ├── github.json + │ │ │ │ ├── google_drive.json + │ │ │ │ ├── qdrant.json + │ │ │ │ ├── redis.json + │ │ │ │ ├── slack.json + │ │ │ │ └── sqlite.json + │ │ │ └── tools/ + │ │ │ ├── get_github_file.py + │ │ │ ├── get_github_file_structure.py + │ │ │ ├── get_github_repo_info.py + │ │ │ └── web_search.py + │ │ ├── archon/ + │ │ │ ├── __init__.py + │ │ │ ├── advisor_agent.py + │ │ │ ├── agent_prompts.py + │ │ │ ├── agent_tools.py + │ │ │ ├── archon_graph.py + │ │ │ ├── crawl_pydantic_ai_docs.py + │ │ │ ├── langgraph.json + │ │ │ ├── pydantic_ai_coder.py + │ │ │ └── refiner_agents/ + │ │ │ ├── agent_refiner_agent.py + │ │ │ ├── prompt_refiner_agent.py + │ │ │ └── tools_refiner_agent.py + │ │ ├── mcp/ + │ │ │ ├── Dockerfile + │ │ │ ├── mcp_server.py + │ │ │ ├── requirements.txt + │ │ │ └── .dockerignore + │ │ ├── streamlit_pages/ + │ │ │ ├── __init__.py + │ │ │ ├── agent_service.py + │ │ │ ├── chat.py + │ │ │ ├── database.py + │ │ │ ├── documentation.py + │ │ │ ├── environment.py + │ │ │ ├── future_enhancements.py + │ │ │ ├── intro.py + │ │ │ ├── mcp.py + │ │ │ └── styles.py + │ │ └── utils/ + │ │ ├── site_pages.sql + │ │ └── utils.py + │ ├── mcp/ + │ │ ├── Dockerfile + │ │ ├── mcp_server.py + │ │ ├── requirements.txt + │ │ └── .dockerignore + │ ├── streamlit_pages/ + │ │ ├── __init__.py + │ │ ├── agent_service.py + │ │ ├── chat.py + │ │ ├── database.py + │ │ ├── documentation.py + │ │ ├── environment.py + │ │ ├── future_enhancements.py + │ │ ├── intro.py + │ │ ├── mcp.py + │ │ └── styles.py + │ ├── utils/ + │ │ ├── site_pages.sql + │ │ └── utils.py + │ ├── .github/ + │ │ ├── dependabot.yml + │ │ ├── ISSUE_TEMPLATE/ + │ │ │ ├── bug_report.md + │ │ │ ├── config.yml + │ │ │ └── feature_request.md + │ │ └── workflows/ + │ │ └── build.yml + │ └── .streamlit/ + │ └── config.toml + ├── PRPs/ + │ └── templates/ + │ └── prp-base.md + ├── python/ + │ ├── Dockerfile.agents + │ ├── Dockerfile.mcp + │ ├── Dockerfile.server + │ ├── pyproject.toml + │ ├── pyrightconfig.json + │ ├── pytest.ini + │ ├── requirements.agents.txt + │ ├── requirements.mcp.txt + │ ├── requirements.server.txt + │ ├── .dockerignore + │ ├── src/ + │ │ ├── __init__.py + │ │ ├── agents/ + │ │ │ ├── __init__.py + │ │ │ ├── base_agent.py + │ │ │ ├── document_agent.py + │ │ │ ├── mcp_client.py + │ │ │ ├── rag_agent.py + │ │ │ └── server.py + │ │ ├── mcp_server/ + │ │ │ ├── __init__.py + │ │ │ ├── mcp_server.py + │ │ │ ├── features/ + │ │ │ │ ├── feature_tools.py + │ │ │ │ ├── documents/ + │ │ │ │ │ ├── __init__.py + │ │ │ │ │ ├── document_tools.py + │ │ │ │ │ └── version_tools.py + │ │ │ │ ├── projects/ + │ │ │ │ │ ├── __init__.py + │ │ │ │ │ └── project_tools.py + │ │ │ │ └── tasks/ + │ │ │ │ ├── __init__.py + │ │ │ │ └── task_tools.py + │ │ │ ├── modules/ + │ │ │ │ ├── __init__.py + │ │ │ │ ├── models.py + │ │ │ │ └── rag_module.py + │ │ │ └── utils/ + │ │ │ ├── __init__.py + │ │ │ ├── error_handling.py + │ │ │ ├── http_client.py + │ │ │ └── timeout_config.py + │ │ └── server/ + │ │ ├── __init__.py + │ │ ├── main.py + │ │ ├── socketio_app.py + │ │ ├── api_routes/ + │ │ │ ├── __init__.py + │ │ │ ├── agent_chat_api.py + │ │ │ ├── bug_report_api.py + │ │ │ ├── coverage_api.py + │ │ │ ├── internal_api.py + │ │ │ ├── knowledge_api.py + │ │ │ ├── mcp_api.py + │ │ │ ├── projects_api.py + │ │ │ ├── settings_api.py + │ │ │ ├── socketio_broadcasts.py + │ │ │ ├── socketio_handlers.py + │ │ │ └── tests_api.py + │ │ ├── config/ + │ │ │ ├── __init__.py + │ │ │ ├── config.py + │ │ │ ├── logfire_config.py + │ │ │ └── service_discovery.py + │ │ ├── middleware/ + │ │ │ └── logging_middleware.py + │ │ ├── services/ + │ │ │ ├── __init__.py + │ │ │ ├── background_task_manager.py + │ │ │ ├── client_manager.py + │ │ │ ├── crawler_manager.py + │ │ │ ├── credential_service.py + │ │ │ ├── llm_provider_service.py + │ │ │ ├── mcp_service_client.py + │ │ │ ├── mcp_session_manager.py + │ │ │ ├── prompt_service.py + │ │ │ ├── source_management_service.py + │ │ │ ├── threading_service.py + │ │ │ ├── crawling/ + │ │ │ │ ├── __init__.py + │ │ │ │ ├── crawling_service.py + │ │ │ │ ├── document_storage_operations.py + │ │ │ │ ├── progress_mapper.py + │ │ │ │ ├── helpers/ + │ │ │ │ │ ├── __init__.py + │ │ │ │ │ ├── site_config.py + │ │ │ │ │ └── url_handler.py + │ │ │ │ └── strategies/ + │ │ │ │ ├── __init__.py + │ │ │ │ ├── batch.py + │ │ │ │ ├── recursive.py + │ │ │ │ ├── single_page.py + │ │ │ │ └── sitemap.py + │ │ │ ├── embeddings/ + │ │ │ │ ├── __init__.py + │ │ │ │ ├── contextual_embedding_service.py + │ │ │ │ ├── embedding_exceptions.py + │ │ │ │ └── embedding_service.py + │ │ │ ├── knowledge/ + │ │ │ │ ├── __init__.py + │ │ │ │ ├── database_metrics_service.py + │ │ │ │ └── knowledge_item_service.py + │ │ │ ├── projects/ + │ │ │ │ ├── __init__.py + │ │ │ │ ├── document_service.py + │ │ │ │ ├── progress_service.py + │ │ │ │ ├── project_creation_service.py + │ │ │ │ ├── project_service.py + │ │ │ │ ├── source_linking_service.py + │ │ │ │ ├── task_service.py + │ │ │ │ └── versioning_service.py + │ │ │ ├── search/ + │ │ │ │ ├── __init__.py + │ │ │ │ ├── agentic_rag_strategy.py + │ │ │ │ ├── base_search_strategy.py + │ │ │ │ ├── hybrid_search_strategy.py + │ │ │ │ ├── keyword_extractor.py + │ │ │ │ ├── rag_service.py + │ │ │ │ └── reranking_strategy.py + │ │ │ └── storage/ + │ │ │ ├── __init__.py + │ │ │ ├── base_storage_service.py + │ │ │ ├── code_storage_service.py + │ │ │ ├── document_storage_service.py + │ │ │ └── storage_services.py + │ │ ├── testing/ + │ │ │ ├── README.md + │ │ │ ├── __init__.py + │ │ │ ├── debug_connectivity.py + │ │ │ ├── prp_data_validator.py + │ │ │ ├── prp_viewer_test.py + │ │ │ └── run_prp_test.sh + │ │ └── utils/ + │ │ ├── __init__.py + │ │ ├── document_processing.py + │ │ └── progress/ + │ │ ├── __init__.py + │ │ └── progress_tracker.py + │ └── tests/ + │ ├── __init__.py + │ ├── conftest.py + │ ├── test_api_essentials.py + │ ├── test_async_background_task_manager.py + │ ├── test_async_credential_service.py + │ ├── test_async_embedding_service.py + │ ├── test_async_llm_provider_service.py + │ ├── test_business_logic.py + │ ├── test_crawl_orchestration_isolated.py + │ ├── test_embedding_service_no_zeros.py + │ ├── test_keyword_extraction.py + │ ├── test_port_configuration.py + │ ├── test_rag_simple.py + │ ├── test_rag_strategies.py + │ ├── test_service_integration.py + │ ├── test_settings_api.py + │ ├── test_supabase_validation.py + │ ├── test_url_handler.py + │ └── mcp_server/ + │ ├── __init__.py + │ ├── features/ + │ │ ├── __init__.py + │ │ ├── test_feature_tools.py + │ │ ├── documents/ + │ │ │ ├── __init__.py + │ │ │ ├── test_document_tools.py + │ │ │ └── test_version_tools.py + │ │ ├── projects/ + │ │ │ ├── __init__.py + │ │ │ └── test_project_tools.py + │ │ └── tasks/ + │ │ ├── __init__.py + │ │ └── test_task_tools.py + │ └── utils/ + │ ├── __init__.py + │ ├── test_error_handling.py + │ └── test_timeout_config.py + ├── .claude/ + │ └── commands/ + │ ├── archon/ + │ │ ├── archon-alpha-review.md + │ │ ├── archon-onboarding.md + │ │ ├── archon-prime-simple.md + │ │ ├── archon-prime.md + │ │ └── archon-rca.md + │ └── prp-commands/ + │ ├── prp-any-cli-create.md + │ ├── prp-any-cli-execute.md + │ ├── prp-claude-code-create.md + │ └── prp-claude-code-execute.md + └── .github/ + ├── pull_request_template.md + ├── ISSUE_TEMPLATE/ + │ └── bug_report.yml + └── workflows/ + ├── ci.yml + ├── claude-fix.yml + └── claude-review.yml + +================================================ +FILE: README.md +================================================ +

+ Archon Main Graphic +

+ +

+ Power up your AI coding assistants with your own custom knowledge base and task management as an MCP server +

+ +

+ Quick Start • + What's Included • + Architecture +

+ +--- + +## 🎯 What is Archon? + +> Archon is currently in beta! Expect things to not work 100%, and please feel free to share any feedback and contribute with fixes/new features! Thank you to everyone for all the excitement we have for Archon already, as well as the bug reports, PRs, and discussions. It's a lot for our small team to get through but we're committed to addressing everything and making Archon into the best tool it possibly can be! + +Archon is the **command center** for AI coding assistants. For you, it's a sleek interface to manage knowledge, context, and tasks for your projects. For the AI coding assistant(s), it's a **Model Context Protocol (MCP) server** to collaborate on and leverage the same knowledge, context, and tasks. Connect Claude Code, Kiro, Cursor, Windsurf, etc. to give your AI agents access to: + +- **Your documentation** (crawled websites, uploaded PDFs/docs) +- **Smart search capabilities** with advanced RAG strategies +- **Task management** integrated with your knowledge base +- **Real-time updates** as you add new content and collaborate with your coding assistant on tasks +- **Much more** coming soon to build Archon into an integrated environment for all context engineering + +This new vision for Archon replaces the old one (the agenteer). Archon used to be the AI agent that builds other agents, and now you can use Archon to do that and more. + +> It doesn't matter what you're building or if it's a new/existing codebase - Archon's knowledge and task management capabilities will improve the output of **any** AI driven coding. + +## 🔗 Important Links + +- **[GitHub Discussions](https://github.com/coleam00/Archon/discussions)** - Join the conversation and share ideas about Archon +- **[Contributing Guide](CONTRIBUTING.md)** - How to get involved and contribute to Archon +- **[Introduction Video](https://youtu.be/8pRc_s2VQIo)** - Getting Started Guide and Vision for Archon +- **[Dynamous AI Mastery](https://dynamous.ai)** - The birthplace of Archon - come join a vibrant community of other early AI adopters all helping each other transform their careers and businesses! + +## Quick Start + +### Prerequisites + +- [Docker Desktop](https://www.docker.com/products/docker-desktop/) +- [Supabase](https://supabase.com/) account (free tier or local Supabase both work) +- [OpenAI API key](https://platform.openai.com/api-keys) (Gemini and Ollama are supported too!) + +### Setup Instructions + +1. **Clone Repository**: + ```bash + git clone https://github.com/coleam00/archon.git + ``` + ```bash + cd archon + ``` +2. **Environment Configuration**: + + ```bash + cp .env.example .env + # Edit .env and add your Supabase credentials: + # SUPABASE_URL=https://your-project.supabase.co + # SUPABASE_SERVICE_KEY=your-service-key-here + ``` + + NOTE: Supabase introduced a new type of service key but use the legacy one (the longer one). + + OPTIONAL: If you want to enable the reranking RAG strategy, uncomment lines 20-22 in `python\requirements.server.txt`. This will significantly increase the size of the Archon Server container which is why it's off by default. + +3. **Database Setup**: In your [Supabase project](https://supabase.com/dashboard) SQL Editor, copy, paste, and execute the contents of `migration/complete_setup.sql` + +4. **Start Services**: + + ```bash + docker-compose up --build -d + ``` + + This starts the core microservices: + - **Server**: Core API and business logic (Port: 8181) + - **MCP Server**: Protocol interface for AI clients (Port: 8051) + - **Agents (coming soon!)**: AI operations and streaming (Port: 8052) + - **UI**: Web interface (Port: 3737) + + Ports are configurable in your .env as well! + +5. **Configure API Keys**: + - Open http://localhost:3737 + - Go to **Settings** → Select your LLM/embedding provider and set the API key (OpenAI is default) + - Test by uploading a document or crawling a website + +## 🔄 Database Reset (Start Fresh if Needed) + +If you need to completely reset your database and start fresh: + +
+⚠️ Reset Database - This will delete ALL data for Archon! + +1. **Run Reset Script**: In your Supabase SQL Editor, run the contents of `migration/RESET_DB.sql` + + ⚠️ WARNING: This will delete all Archon specific tables and data! Nothing else will be touched in your DB though. + +2. **Rebuild Database**: After reset, run `migration/complete_setup.sql` to create all the tables again. + +3. **Restart Services**: + + ```bash + docker-compose up -d + ``` + +4. **Reconfigure**: + - Select your LLM/embedding provider and set the API key again + - Re-upload any documents or re-crawl websites + +The reset script safely removes all tables, functions, triggers, and policies with proper dependency handling. + +
+ +## ⚡ Quick Test + +Once everything is running: + +1. **Test Web Crawling**: Go to http://localhost:3737 → Knowledge Base → "Crawl Website" → Enter a doc URL (such as https://ai.pydantic.dev/llms-full.txt) +2. **Test Document Upload**: Knowledge Base → Upload a PDF +3. **Test Projects**: Projects → Create a new project and add tasks +4. **Integrate with your AI coding assistant**: MCP Dashboard → Copy connection config for your AI coding assistant + +## 📚 Documentation + +### Core Services + +| Service | Container Name | Default URL | Purpose | +| ------------------ | -------------- | --------------------- | --------------------------------- | +| **Web Interface** | archon-ui | http://localhost:3737 | Main dashboard and controls | +| **API Service** | archon-server | http://localhost:8181 | Web crawling, document processing | +| **MCP Server** | archon-mcp | http://localhost:8051 | Model Context Protocol interface | +| **Agents Service** | archon-agents | http://localhost:8052 | AI/ML operations, reranking | + +## What's Included + +### 🧠 Knowledge Management + +- **Smart Web Crawling**: Automatically detects and crawls entire documentation sites, sitemaps, and individual pages +- **Document Processing**: Upload and process PDFs, Word docs, markdown files, and text documents with intelligent chunking +- **Code Example Extraction**: Automatically identifies and indexes code examples from documentation for enhanced search +- **Vector Search**: Advanced semantic search with contextual embeddings for precise knowledge retrieval +- **Source Management**: Organize knowledge by source, type, and tags for easy filtering + +### 🤖 AI Integration + +- **Model Context Protocol (MCP)**: Connect any MCP-compatible client (Claude Code, Cursor, even non-AI coding assistants like Claude Desktop) +- **10 MCP Tools**: Comprehensive yet simple set of tools for RAG queries, task management, and project operations +- **Multi-LLM Support**: Works with OpenAI, Ollama, and Google Gemini models +- **RAG Strategies**: Hybrid search, contextual embeddings, and result reranking for optimal AI responses +- **Real-time Streaming**: Live responses from AI agents with progress tracking + +### 📋 Project & Task Management + +- **Hierarchical Projects**: Organize work with projects, features, and tasks in a structured workflow +- **AI-Assisted Creation**: Generate project requirements and tasks using integrated AI agents +- **Document Management**: Version-controlled documents with collaborative editing capabilities +- **Progress Tracking**: Real-time updates and status management across all project activities + +### 🔄 Real-time Collaboration + +- **WebSocket Updates**: Live progress tracking for crawling, processing, and AI operations +- **Multi-user Support**: Collaborative knowledge building and project management +- **Background Processing**: Asynchronous operations that don't block the user interface +- **Health Monitoring**: Built-in service health checks and automatic reconnection + +## Architecture + +### Microservices Structure + +Archon uses true microservices architecture with clear separation of concerns: + +``` +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ Frontend UI │ │ Server (API) │ │ MCP Server │ │ Agents Service │ +│ │ │ │ │ │ │ │ +│ React + Vite │◄──►│ FastAPI + │◄──►│ Lightweight │◄──►│ PydanticAI │ +│ Port 3737 │ │ SocketIO │ │ HTTP Wrapper │ │ Port 8052 │ +│ │ │ Port 8181 │ │ Port 8051 │ │ │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ └─────────────────┘ + │ │ │ │ + └────────────────────────┼────────────────────────┼────────────────────────┘ + │ │ + ┌─────────────────┐ │ + │ Database │ │ + │ │ │ + │ Supabase │◄──────────────┘ + │ PostgreSQL │ + │ PGVector │ + └─────────────────┘ +``` + +### Service Responsibilities + +| Service | Location | Purpose | Key Features | +| -------------- | -------------------- | ---------------------------- | ------------------------------------------------------------------ | +| **Frontend** | `archon-ui-main/` | Web interface and dashboard | React, TypeScript, TailwindCSS, Socket.IO client | +| **Server** | `python/src/server/` | Core business logic and APIs | FastAPI, service layer, Socket.IO broadcasts, all ML/AI operations | +| **MCP Server** | `python/src/mcp/` | MCP protocol interface | Lightweight HTTP wrapper, 10 MCP tools, session management | +| **Agents** | `python/src/agents/` | PydanticAI agent hosting | Document and RAG agents, streaming responses | + +### Communication Patterns + +- **HTTP-based**: All inter-service communication uses HTTP APIs +- **Socket.IO**: Real-time updates from Server to Frontend +- **MCP Protocol**: AI clients connect to MCP Server via SSE or stdio +- **No Direct Imports**: Services are truly independent with no shared code dependencies + +### Key Architectural Benefits + +- **Lightweight Containers**: Each service contains only required dependencies +- **Independent Scaling**: Services can be scaled independently based on load +- **Development Flexibility**: Teams can work on different services without conflicts +- **Technology Diversity**: Each service uses the best tools for its specific purpose + +## 🔧 Configuring Custom Ports & Hostname + +By default, Archon services run on the following ports: + +- **Archon-UI**: 3737 +- **Archon-Server**: 8181 +- **Archon-MCP**: 8051 +- **Archon-Agents**: 8052 +- **Archon-Docs**: 3838 (optional) + +### Changing Ports + +To use custom ports, add these variables to your `.env` file: + +```bash +# Service Ports Configuration +ARCHON_UI_PORT=3737 +ARCHON_SERVER_PORT=8181 +ARCHON_MCP_PORT=8051 +ARCHON_AGENTS_PORT=8052 +ARCHON_DOCS_PORT=3838 +``` + +Example: Running on different ports: + +```bash +ARCHON_SERVER_PORT=8282 +ARCHON_MCP_PORT=8151 +``` + +### Configuring Hostname + +By default, Archon uses `localhost` as the hostname. You can configure a custom hostname or IP address by setting the `HOST` variable in your `.env` file: + +```bash +# Hostname Configuration +HOST=localhost # Default + +# Examples of custom hostnames: +HOST=192.168.1.100 # Use specific IP address +HOST=archon.local # Use custom domain +HOST=myserver.com # Use public domain +``` + +This is useful when: + +- Running Archon on a different machine and accessing it remotely +- Using a custom domain name for your installation +- Deploying in a network environment where `localhost` isn't accessible + +After changing hostname or ports: + +1. Restart Docker containers: `docker-compose down && docker-compose up -d` +2. Access the UI at: `http://${HOST}:${ARCHON_UI_PORT}` +3. Update your AI client configuration with the new hostname and MCP port + +## 🔧 Development + +For development with hot reload: + +```bash +# Backend services (with auto-reload) +docker-compose up archon-server archon-mcp archon-agents --build + +# Frontend (with hot reload) +cd archon-ui-main && npm run dev + +# Documentation (with hot reload) +cd docs && npm start +``` + +**Note**: The backend services are configured with `--reload` flag in their uvicorn commands and have source code mounted as volumes for automatic hot reloading when you make changes. + +## 📄 License + +Archon Community License (ACL) v1.2 - see [LICENSE](LICENSE) file for details. + +**TL;DR**: Archon is free, open, and hackable. Run it, fork it, share it - just don't sell it as-a-service without permission. + + + +================================================ +FILE: CLAUDE.md +================================================ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Alpha Development Guidelines + +**Local-only deployment** - each user runs their own instance. + +### Core Principles + +- **No backwards compatibility** - remove deprecated code immediately +- **Detailed errors over graceful failures** - we want to identify and fix issues fast +- **Break things to improve them** - alpha is for rapid iteration + +### Error Handling + +**Core Principle**: In alpha, we need to intelligently decide when to fail hard and fast to quickly address issues, and when to allow processes to complete in critical services despite failures. Read below carefully and make intelligent decisions on a case-by-case basis. + +#### When to Fail Fast and Loud (Let it Crash!) + +These errors should stop execution and bubble up immediately: + +- **Service startup failures** - If credentials, database, or any service can't initialize, the system should crash with a clear error +- **Missing configuration** - Missing environment variables or invalid settings should stop the system +- **Database connection failures** - Don't hide connection issues, expose them +- **Authentication/authorization failures** - Security errors must be visible and halt the operation +- **Data corruption or validation errors** - Never silently accept bad data, Pydantic should raise +- **Critical dependencies unavailable** - If a required service is down, fail immediately +- **Invalid data that would corrupt state** - Never store zero embeddings, null foreign keys, or malformed JSON + +#### When to Complete but Log Detailed Errors + +These operations should continue but track and report failures clearly: + +- **Batch processing** - When crawling websites or processing documents, complete what you can and report detailed failures for each item +- **Background tasks** - Embedding generation, async jobs should finish the queue but log failures +- **WebSocket events** - Don't crash on a single event failure, log it and continue serving other clients +- **Optional features** - If projects/tasks are disabled, log and skip rather than crash +- **External API calls** - Retry with exponential backoff, then fail with a clear message about what service failed and why + +#### Critical Nuance: Never Accept Corrupted Data + +When a process should continue despite failures, it must **skip the failed item entirely** rather than storing corrupted data: + +**❌ WRONG - Silent Corruption:** + +```python +try: + embedding = create_embedding(text) +except Exception as e: + embedding = [0.0] * 1536 # NEVER DO THIS - corrupts database + store_document(doc, embedding) +``` + +**✅ CORRECT - Skip Failed Items:** + +```python +try: + embedding = create_embedding(text) + store_document(doc, embedding) # Only store on success +except Exception as e: + failed_items.append({'doc': doc, 'error': str(e)}) + logger.error(f"Skipping document {doc.id}: {e}") + # Continue with next document, don't store anything +``` + +**✅ CORRECT - Batch Processing with Failure Tracking:** + +```python +def process_batch(items): + results = {'succeeded': [], 'failed': []} + + for item in items: + try: + result = process_item(item) + results['succeeded'].append(result) + except Exception as e: + results['failed'].append({ + 'item': item, + 'error': str(e), + 'traceback': traceback.format_exc() + }) + logger.error(f"Failed to process {item.id}: {e}") + + # Always return both successes and failures + return results +``` + +#### Error Message Guidelines + +- Include context about what was being attempted when the error occurred +- Preserve full stack traces with `exc_info=True` in Python logging +- Use specific exception types, not generic Exception catching +- Include relevant IDs, URLs, or data that helps debug the issue +- Never return None/null to indicate failure - raise an exception with details +- For batch operations, always report both success count and detailed failure list + +### Code Quality + +- Remove dead code immediately rather than maintaining it - no backward compatibility or legacy functions +- Prioritize functionality over production-ready patterns +- Focus on user experience and feature completeness +- When updating code, don't reference what is changing (avoid keywords like LEGACY, CHANGED, REMOVED), instead focus on comments that document just the functionality of the code + +## Architecture Overview + +Archon V2 Alpha is a microservices-based knowledge management system with MCP (Model Context Protocol) integration: + +- **Frontend (port 3737)**: React + TypeScript + Vite + TailwindCSS +- **Main Server (port 8181)**: FastAPI + Socket.IO for real-time updates +- **MCP Server (port 8051)**: Lightweight HTTP-based MCP protocol server +- **Agents Service (port 8052)**: PydanticAI agents for AI/ML operations +- **Database**: Supabase (PostgreSQL + pgvector for embeddings) + +## Development Commands + +### Frontend (archon-ui-main/) + +```bash +npm run dev # Start development server on port 3737 +npm run build # Build for production +npm run lint # Run ESLint +npm run test # Run Vitest tests +npm run test:coverage # Run tests with coverage report +``` + +### Backend (python/) + +```bash +# Using uv package manager +uv sync # Install/update dependencies +uv run pytest # Run tests +uv run python -m src.server.main # Run server locally + +# With Docker +docker-compose up --build -d # Start all services +docker-compose logs -f # View logs +docker-compose restart # Restart services +``` + +### Testing + +```bash +# Frontend tests (from archon-ui-main/) +npm run test:coverage:stream # Run with streaming output +npm run test:ui # Run with Vitest UI + +# Backend tests (from python/) +uv run pytest tests/test_api_essentials.py -v +uv run pytest tests/test_service_integration.py -v +``` + +## Key API Endpoints + +### Knowledge Base + +- `POST /api/knowledge/crawl` - Crawl a website +- `POST /api/knowledge/upload` - Upload documents (PDF, DOCX, MD) +- `GET /api/knowledge/items` - List knowledge items +- `POST /api/knowledge/search` - RAG search + +### MCP Integration + +- `GET /api/mcp/health` - MCP server status +- `POST /api/mcp/tools/{tool_name}` - Execute MCP tool +- `GET /api/mcp/tools` - List available tools + +### Projects & Tasks (when enabled) + +- `GET /api/projects` - List projects +- `POST /api/projects` - Create project +- `GET /api/projects/{id}/tasks` - Get project tasks +- `POST /api/projects/{id}/tasks` - Create task + +## Socket.IO Events + +Real-time updates via Socket.IO on port 8181: + +- `crawl_progress` - Website crawling progress +- `project_creation_progress` - Project setup progress +- `task_update` - Task status changes +- `knowledge_update` - Knowledge base changes + +## Environment Variables + +Required in `.env`: + +```bash +SUPABASE_URL=https://your-project.supabase.co +SUPABASE_SERVICE_KEY=your-service-key-here +``` + +Optional: + +```bash +OPENAI_API_KEY=your-openai-key # Can be set via UI +LOGFIRE_TOKEN=your-logfire-token # For observability +LOG_LEVEL=INFO # DEBUG, INFO, WARNING, ERROR +``` + +## File Organization + +### Frontend Structure + +- `src/components/` - Reusable UI components +- `src/pages/` - Main application pages +- `src/services/` - API communication and business logic +- `src/hooks/` - Custom React hooks +- `src/contexts/` - React context providers + +### Backend Structure + +- `src/server/` - Main FastAPI application +- `src/server/api_routes/` - API route handlers +- `src/server/services/` - Business logic services +- `src/mcp/` - MCP server implementation +- `src/agents/` - PydanticAI agent implementations + +## Database Schema + +Key tables in Supabase: + +- `sources` - Crawled websites and uploaded documents +- `documents` - Processed document chunks with embeddings +- `projects` - Project management (optional feature) +- `tasks` - Task tracking linked to projects +- `code_examples` - Extracted code snippets + +## Common Development Tasks + +### Add a new API endpoint + +1. Create route handler in `python/src/server/api_routes/` +2. Add service logic in `python/src/server/services/` +3. Include router in `python/src/server/main.py` +4. Update frontend service in `archon-ui-main/src/services/` + +### Add a new UI component + +1. Create component in `archon-ui-main/src/components/` +2. Add to page in `archon-ui-main/src/pages/` +3. Include any new API calls in services +4. Add tests in `archon-ui-main/test/` + +### Debug MCP connection issues + +1. Check MCP health: `curl http://localhost:8051/health` +2. View MCP logs: `docker-compose logs archon-mcp` +3. Test tool execution via UI MCP page +4. Verify Supabase connection and credentials + +## Code Quality Standards + +We enforce code quality through automated linting and type checking: + +- **Python 3.12** with 120 character line length +- **Ruff** for linting - checks for errors, warnings, unused imports, and code style +- **Mypy** for type checking - ensures type safety across the codebase +- **Auto-formatting** on save in IDEs to maintain consistent style +- Run `uv run ruff check` and `uv run mypy src/` locally before committing + +## MCP Tools Available + +When connected to Cursor/Windsurf: + +- `archon:perform_rag_query` - Search knowledge base +- `archon:search_code_examples` - Find code snippets +- `archon:manage_project` - Project operations +- `archon:manage_task` - Task management +- `archon:get_available_sources` - List knowledge sources + +## Important Notes + +- Projects feature is optional - toggle in Settings UI +- All services communicate via HTTP, not gRPC +- Socket.IO handles all real-time updates +- Frontend uses Vite proxy for API calls in development +- Python backend uses `uv` for dependency management +- Docker Compose handles service orchestration + + + +================================================ +FILE: CONTRIBUTING.md +================================================ +# Contributing to Archon + +Help us build the definitive knowledge and task management engine for AI coding assistants! This guide shows you how to contribute new features, bug fixes, and improvements to the Archon platform. + +## 🎯 What is Archon? + +Archon is a **microservices-based engine** that provides AI coding assistants with access to your documentation, project knowledge, and task management through the Model Context Protocol (MCP). The platform consists of four main services that work together to deliver comprehensive knowledge management and project automation. + +## 🏗️ Architecture Overview + +### Microservices Structure + +Archon uses true microservices architecture with clear separation of concerns: + +``` +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ Frontend UI │ │ Server (API) │ │ MCP Server │ │ Agents Service │ +│ │ │ │ │ │ │ │ +│ React + Vite │◄──►│ FastAPI + │◄──►│ Lightweight │◄──►│ PydanticAI │ +│ Port 3737 │ │ SocketIO │ │ HTTP Wrapper │ │ Port 8052 │ +│ │ │ Port 8181 │ │ Port 8051 │ │ │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ └─────────────────┘ + │ │ │ │ + └────────────────────────┼────────────────────────┼────────────────────────┘ + │ │ + ┌─────────────────┐ │ + │ Database │ │ + │ │ │ + │ Supabase │◄──────────────┘ + │ PostgreSQL │ + │ PGVector │ + └─────────────────┘ +``` + +### Service Responsibilities + +| Service | Location | Purpose | Key Features | +| -------------- | -------------------- | ---------------------------- | -------------------------------------------------------------------------- | +| **Frontend** | `archon-ui-main/` | Web interface and dashboard | React, TypeScript, TailwindCSS, Socket.IO client | +| **Server** | `python/src/server/` | Core business logic and APIs | FastAPI, service layer, Socket.IO broadcasts, all LLM/embedding operations | +| **MCP Server** | `python/src/mcp/` | MCP protocol interface | Lightweight HTTP wrapper, 14 MCP tools, session management | +| **Agents** | `python/src/agents/` | PydanticAI agent hosting | Document and RAG agents, streaming responses | + +### Communication Patterns + +- **HTTP-based**: All inter-service communication uses HTTP APIs +- **Socket.IO**: Real-time updates from Server to Frontend +- **MCP Protocol**: AI clients connect to MCP Server via SSE or stdio +- **No Direct Imports**: Services are truly independent with no shared code dependencies + +## 🚀 Quick Start for Contributors + +### Prerequisites + +- [Docker Desktop](https://www.docker.com/products/docker-desktop/) +- [Supabase](https://supabase.com/) account (free tier works) +- [OpenAI API key](https://platform.openai.com/api-keys) or alternative LLM provider +- Basic knowledge of Python (FastAPI) and TypeScript (React) + +### Initial Setup + +After forking the repository, you'll need to: + +1. **Environment Configuration** + + ```bash + cp .env.example .env + # Edit .env with your Supabase credentials + ``` + +2. **Database Setup** + - Run `migration/complete_setup.sql` in your Supabase SQL Editor + +3. **Start Development Environment** + + ```bash + docker-compose up --build -d + ``` + +4. **Configure API Keys** + - Open http://localhost:3737 + - Go to Settings → Add your OpenAI API key + +## 🔄 Contribution Process + +### 1. Choose Your Contribution + +**Bug Fixes:** + +- Check existing issues for reported bugs +- Create detailed reproduction steps +- Fix in smallest possible scope + +**New Features:** + +- Optional: Open an issue first to discuss the feature +- Get feedback on approach and architecture (from maintainers and/or AI coding assistants) +- Break large features into smaller PRs + +**Documentation:** + +- Look for gaps in current documentation +- Focus on user-facing improvements +- Update both code docs and user guides + +### 2. Development Process + +1. **Fork the Repository** + - Go to https://github.com/coleam00/archon + - Click the "Fork" button in the top right corner + - This creates your own copy of the repository + + ```bash + # Clone your fork (replace 'your-username' with your GitHub username) + git clone https://github.com/your-username/archon.git + cd archon + + # Add upstream remote to sync with main repository later + git remote add upstream https://github.com/coleam00/archon.git + ``` + +2. **🤖 AI Coding Assistant Setup** + + **IMPORTANT**: If you're using AI coding assistants to help contribute to Archon, set up our global rules for optimal results. + - **Claude Code**: ✅ Already configured! The `CLAUDE.md` file is automatically used + - **Cursor**: Copy `CLAUDE.md` content to a new `.cursorrules` file in the project root + - **Windsurf**: Copy `CLAUDE.md` content to a new `.windsurfrules` file in the project root + - **Other assistants**: Copy `CLAUDE.md` content to your assistant's global rules/context file + + These rules contain essential context about Archon's architecture, service patterns, MCP implementation, and development best practices. Using them will help your AI assistant follow our conventions and implement features correctly. + +3. **Create Feature Branch** + + **Best Practice**: Always create a feature branch rather than working directly on main. This keeps your main branch clean and makes it easier to sync with the upstream repository. + + ```bash + git checkout -b feature/your-feature-name + # or + git checkout -b fix/bug-description + ``` + +4. **Make Your Changes** + - Follow the service architecture patterns + - Add tests for new functionality + - Update documentation as needed + +5. **Verify Your Changes** + - Run full test suite + - Test manually via Docker environment + - Verify no regressions in existing features + +### 3. Submit Pull Request + +1. **Push to Your Fork** + + ```bash + # First time pushing this branch + git push -u origin feature/your-feature-name + + # For subsequent pushes to the same branch + git push + ``` + +2. **Create Pull Request via GitHub UI** + - Go to your fork on GitHub (https://github.com/your-username/archon) + - Click "Contribute" then "Open pull request" + - GitHub will automatically detect your branch and show a comparison + - The PR template will be automatically filled in the description + - Review the template and fill out the required sections + - Click "Create pull request" + +3. **Testing Requirements** + + **Before submitting, ensure:** + - [ ] All existing tests pass + - [ ] New tests added for new functionality + - [ ] Manual testing of affected user flows + - [ ] Docker builds succeed for all services + + **Test commands:** + + ```bash + # Backend tests + cd python && python -m pytest + + # Frontend tests + cd archon-ui-main && npm run test + + # Full integration test + docker-compose up --build -d + # Test via UI at http://localhost:3737 + ``` + +4. **Review Process** + - Automated tests will run on your PR + - Maintainers will review code and architecture + - Address feedback and iterate as needed + +## 📋 Contribution Areas + +### 🔧 Backend Services (Python) + +**When to contribute:** + +- Adding new API endpoints or business logic +- Implementing new MCP tools +- Creating new service classes or utilities +- Improving crawling, embedding, or search functionality (everything for RAG) + +**Key locations:** + +- **Service Layer**: `python/src/server/services/` - Core business logic organized by domain +- **API Endpoints**: `python/src/server/api_routes/` - REST API route handlers +- **MCP Tools**: `python/src/mcp/modules/` - MCP protocol implementations +- **Agents**: `python/src/agents/` - PydanticAI agent implementations + +**Development patterns:** + +- Services use dependency injection with `supabase_client` parameter +- Use async/await for I/O operations, sync for pure logic +- Follow service → API → MCP layer separation + +### 🎨 Frontend (React/TypeScript) + +**When to contribute:** + +- Adding new UI components or pages +- Implementing real-time features with Socket.IO +- Creating new service integrations +- Improving user experience and accessibility + +**Key locations:** + +- **Components**: `archon-ui-main/src/components/` - Reusable UI components organized by feature +- **Pages**: `archon-ui-main/src/pages/` - Main application routes +- **Services**: `archon-ui-main/src/services/` - API communication and business logic +- **Contexts**: `archon-ui-main/src/contexts/` - React context providers for global state + +**Development patterns:** + +- Context-based state management (no Redux) +- Service layer abstraction for API calls +- Socket.IO for real-time updates +- TailwindCSS for styling with custom design system + +### 🐳 Infrastructure (Docker/DevOps) + +**When to contribute:** + +- Optimizing container builds or sizes +- Improving service orchestration +- Adding new environment configurations +- Enhancing health checks and monitoring + +**Key locations:** + +- **Docker**: `python/Dockerfile.*` - Service-specific containers +- **Compose**: `docker-compose.yml` - Service orchestration +- **Config**: `.env.example` - Environment variable documentation + +### 📚 Documentation + +**When to contribute:** + +- Adding API documentation +- Creating deployment guides +- Writing feature tutorials +- Improving architecture explanations + +**Key locations:** + +- **Docs Site**: `docs/docs/` - Docusaurus-based documentation +- **API Docs**: Auto-generated from FastAPI endpoints +- **README**: Main project documentation + +## 🛠️ Development Workflows + +### Backend Development (Python) + +1. **Adding a New Service** + + ```bash + # Create service class in appropriate domain + python/src/server/services/your_domain/your_service.py + + # Add API endpoints + python/src/server/api_routes/your_api.py + + # Optional: Add MCP tools + python/src/mcp/modules/your_module.py + ``` + +2. **Testing Your Changes** + + ```bash + # Run Python tests + cd python && python -m pytest tests/ + + # Run specific test categories + python -m pytest -m unit # Unit tests only + python -m pytest -m integration # Integration tests only + ``` + +3. **Code Quality** + ```bash + # We encourage you to use linters for all code + # Follow service patterns from existing code + ``` + +### Frontend Development (React) + +1. **Adding a New Component** + + ```bash + # Create in appropriate category + archon-ui-main/src/components/your-category/YourComponent.tsx + + # Add to appropriate page or parent component + archon-ui-main/src/pages/YourPage.tsx + ``` + +2. **Testing Your Changes** + + ```bash + # Run frontend tests + cd archon-ui-main && npm run test + + # Run with coverage + npm run test:coverage + + # Run in UI mode + npm run test:ui + ``` + +3. **Development Server** + ```bash + # For faster iteration, run frontend locally + cd archon-ui-main && npm run dev + # Still connects to Docker backend services + ``` + +## ✅ Quality Standards + +### Code Requirements + +1. **Backend (Python)** + - Follow existing service patterns and dependency injection + - Use type hints and proper async/await patterns + - Include unit tests for new business logic + - Update API documentation if adding endpoints + +2. **Frontend (TypeScript)** + - Use TypeScript with proper typing + - Follow existing component patterns and context usage + - Include component tests for new UI features + - Ensure responsive design and accessibility + +3. **Documentation** + - Update relevant docs for user-facing changes + - Include inline code documentation for complex logic + - Add migration notes for breaking changes + +### Performance Considerations + +- **Service Layer**: Keep business logic efficient, use async for I/O +- **API Responses**: Consider pagination for large datasets +- **Real-time Updates**: Use Socket.IO rooms appropriately +- **Database**: Consider indexes for new query patterns + +## 🏛️ Architectural Guidelines + +### Service Design Principles + +1. **Single Responsibility**: Each service has a focused purpose +2. **HTTP Communication**: No direct imports between services +3. **Database Centralization**: Supabase as single source of truth +4. **Real-time Updates**: Socket.IO for live collaboration features + +### Adding New MCP Tools + +**Tool Pattern:** + +```python +@mcp.tool() +async def your_new_tool(ctx: Context, param: str) -> str: + """ + Tool description for AI clients. + + Args: + param: Description of parameter + + Returns: + JSON string with results + """ + async with httpx.AsyncClient() as client: + response = await client.post(f"{API_URL}/api/your-endpoint", + json={"param": param}) + return response.json() +``` + +### Adding New Service Classes + +**Service Pattern:** + +```python +class YourService: + def __init__(self, supabase_client=None): + self.supabase_client = supabase_client or get_supabase_client() + + def your_operation(self, param: str) -> Tuple[bool, Dict[str, Any]]: + try: + # Business logic here + result = self.supabase_client.table("table").insert(data).execute() + return True, {"data": result.data} + except Exception as e: + logger.error(f"Error in operation: {e}") + return False, {"error": str(e)} +``` + +## 🤝 Community Standards + +### Communication Guidelines + +- **Be Constructive**: Focus on improving the codebase and user experience +- **Be Specific**: Provide detailed examples and reproduction steps +- **Be Collaborative**: Welcome diverse perspectives and approaches +- **Be Patient**: Allow time for review and discussion + +### Code Review Process + +**As a Contributor:** + +- Write clear PR descriptions +- Respond promptly to review feedback +- Test your changes thoroughly + +**As a Reviewer:** + +- Focus on architecture, correctness, and user impact +- Provide specific, actionable feedback +- Acknowledge good practices and improvements + +## 📞 Getting Help + +- **GitHub Issues**: For bugs, feature requests, and questions +- **Architecture Questions**: Use the GitHub discussions + +## 🎖️ Recognition + +Contributors receive: + +- **Attribution**: Recognition in release notes and documentation +- **Maintainer Track**: Path to maintainer role for consistent contributors +- **Community Impact**: Help improve AI development workflows for thousands of users + +--- + +**Ready to contribute?** Start by exploring the codebase, reading the architecture documentation, and finding an area that interests you. Every contribution makes Archon better for the entire AI development community. + + + +================================================ +FILE: docker-compose.docs.yml +================================================ +# Optional Documentation Service +# Run with: docker-compose -f docker-compose.yml -f docker-compose.docs.yml up -d + +services: + # Documentation + docs: + build: + context: ./docs + dockerfile: Dockerfile + container_name: Archon-Docs + ports: + - "${ARCHON_DOCS_PORT:-3838}:80" + networks: + - app-network + + +================================================ +FILE: docker-compose.yml +================================================ +services: + # Server Service (FastAPI + Socket.IO + Crawling) + archon-server: + build: + context: ./python + dockerfile: Dockerfile.server + args: + BUILDKIT_INLINE_CACHE: 1 + ARCHON_SERVER_PORT: ${ARCHON_SERVER_PORT:-8181} + container_name: Archon-Server + ports: + - "${ARCHON_SERVER_PORT:-8181}:${ARCHON_SERVER_PORT:-8181}" + environment: + - SUPABASE_URL=${SUPABASE_URL} + - SUPABASE_SERVICE_KEY=${SUPABASE_SERVICE_KEY} + - OPENAI_API_KEY=${OPENAI_API_KEY:-} + - LOGFIRE_TOKEN=${LOGFIRE_TOKEN:-} + - SERVICE_DISCOVERY_MODE=docker_compose + - LOG_LEVEL=${LOG_LEVEL:-INFO} + - ARCHON_SERVER_PORT=${ARCHON_SERVER_PORT:-8181} + - ARCHON_MCP_PORT=${ARCHON_MCP_PORT:-8051} + - ARCHON_AGENTS_PORT=${ARCHON_AGENTS_PORT:-8052} + networks: + - app-network + volumes: + - /var/run/docker.sock:/var/run/docker.sock # Docker socket for MCP container control + - ./python/src:/app/src # Mount source code for hot reload + - ./python/tests:/app/tests # Mount tests for UI test execution + extra_hosts: + - "host.docker.internal:host-gateway" + command: + [ + "python", + "-m", + "uvicorn", + "src.server.main:socket_app", + "--host", + "0.0.0.0", + "--port", + "${ARCHON_SERVER_PORT:-8181}", + "--reload", + ] + healthcheck: + test: + [ + "CMD", + "sh", + "-c", + 'python -c "import urllib.request; urllib.request.urlopen(''http://localhost:${ARCHON_SERVER_PORT:-8181}/health'')"', + ] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + + # Lightweight MCP Server Service (HTTP-based) + archon-mcp: + build: + context: ./python + dockerfile: Dockerfile.mcp + args: + BUILDKIT_INLINE_CACHE: 1 + ARCHON_MCP_PORT: ${ARCHON_MCP_PORT:-8051} + container_name: Archon-MCP + ports: + - "${ARCHON_MCP_PORT:-8051}:${ARCHON_MCP_PORT:-8051}" + environment: + - SUPABASE_URL=${SUPABASE_URL} + - SUPABASE_SERVICE_KEY=${SUPABASE_SERVICE_KEY} + - LOGFIRE_TOKEN=${LOGFIRE_TOKEN:-} + - SERVICE_DISCOVERY_MODE=docker_compose + - TRANSPORT=sse + - LOG_LEVEL=${LOG_LEVEL:-INFO} + # MCP needs to know where to find other services + - API_SERVICE_URL=http://archon-server:${ARCHON_SERVER_PORT:-8181} + - AGENTS_SERVICE_URL=http://archon-agents:${ARCHON_AGENTS_PORT:-8052} + - ARCHON_MCP_PORT=${ARCHON_MCP_PORT:-8051} + - ARCHON_SERVER_PORT=${ARCHON_SERVER_PORT:-8181} + - ARCHON_AGENTS_PORT=${ARCHON_AGENTS_PORT:-8052} + networks: + - app-network + depends_on: + - archon-server + - archon-agents + extra_hosts: + - "host.docker.internal:host-gateway" + healthcheck: + test: + [ + "CMD", + "sh", + "-c", + 'python -c "import socket; s=socket.socket(); s.connect((''localhost'', ${ARCHON_MCP_PORT:-8051})); s.close()"', + ] + interval: 30s + timeout: 10s + retries: 3 + start_period: 60s # Give dependencies time to start + + # AI Agents Service (ML/Reranking) + archon-agents: + build: + context: ./python + dockerfile: Dockerfile.agents + args: + BUILDKIT_INLINE_CACHE: 1 + ARCHON_AGENTS_PORT: ${ARCHON_AGENTS_PORT:-8052} + container_name: Archon-Agents + ports: + - "${ARCHON_AGENTS_PORT:-8052}:${ARCHON_AGENTS_PORT:-8052}" + environment: + - SUPABASE_URL=${SUPABASE_URL} + - SUPABASE_SERVICE_KEY=${SUPABASE_SERVICE_KEY} + - OPENAI_API_KEY=${OPENAI_API_KEY:-} + - LOGFIRE_TOKEN=${LOGFIRE_TOKEN:-} + - SERVICE_DISCOVERY_MODE=docker_compose + - LOG_LEVEL=${LOG_LEVEL:-INFO} + - ARCHON_AGENTS_PORT=${ARCHON_AGENTS_PORT:-8052} + networks: + - app-network + healthcheck: + test: + [ + "CMD", + "sh", + "-c", + 'python -c "import urllib.request; urllib.request.urlopen(''http://localhost:${ARCHON_AGENTS_PORT:-8052}/health'')"', + ] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + + # Frontend + frontend: + build: ./archon-ui-main + container_name: Archon-UI + ports: + - "${ARCHON_UI_PORT:-3737}:5173" + environment: + - VITE_API_URL=http://${HOST:-localhost}:${ARCHON_SERVER_PORT:-8181} + - ARCHON_SERVER_PORT=${ARCHON_SERVER_PORT:-8181} + - HOST=${HOST:-localhost} + networks: + - app-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5173"] + interval: 30s + timeout: 10s + retries: 3 + volumes: + - ./archon-ui-main/src:/app/src + - ./archon-ui-main/public:/app/public + depends_on: + - archon-server + +networks: + app-network: + driver: bridge + + + +================================================ +FILE: LICENSE +================================================ +Archon Community License (ACL) v1.2 + +Copyright © 2025 The Archon Project Community +Maintained by the [Dynamous community](https://dynamous.ai) + +Archon is **free, open, and hackable.** Run it, fork it, and share it — no strings attached — except one: **don’t sell it as‑a‑service without talking to us first.** + +--- + +### 1  You Can + +* **Run** Archon anywhere, for anything, for free. +* **Study & tweak** the code, add features, change the UI—go wild. +* **Share** your changes or forks publicly (must keep this license in place). + +### 2  Please Do + +* Keep this license notice and a link back to the main repo. +* Mark clearly if you’ve modified Archon. + +### 3  You Can’t (Without Permission) + +* Charge money for Archon itself—e.g. paid downloads, paywalled builds, or subscriptions. +* Offer Archon (original or modified) as a hosted or managed service that others can sign up for. +* Bundle Archon into another paid product. + +> **Consulting/support is totally fine.** Get paid to install, customise, or teach Archon as long as your clients don’t get a hosted Archon instance run by you. + +### 4  No Warranty + +Archon comes **as‑is** with **no warranty** of any kind. + +### 5  Limitation of Liability + +We’re **not liable** for any damages resulting from using Archon. + +### 6  Breaking the Rules + +If you violate these terms and don’t fix it within **30 days** after we let you know, your rights under this license end. + + + +================================================ +FILE: .dockerignore +================================================ +crawl4ai_mcp.egg-info +__pycache__ +.venv +.env + + +================================================ +FILE: .env.example +================================================ +# Minimal startup configuration - only Supabase connection required +# All other settings (API keys, model choices, RAG flags) are managed via the Settings page + +# Get your SUPABASE_URL from the Data API section of your Supabase project settings - +# https://supabase.com/dashboard/project//settings/api +SUPABASE_URL= + +# ⚠️ CRITICAL: You MUST use the SERVICE ROLE key, NOT the Anon key! ⚠️ +# +# COMMON MISTAKE: Using the anon (public) key will cause ALL saves to fail with "permission denied"! +# +# How to get the CORRECT key: +# 1. Go to: https://supabase.com/dashboard/project//settings/api +# 2. In the Settings menu, click on "API keys" +# 3. Find "Project API keys" section +# 4. You will see TWO keys - choose carefully: +# ❌ anon (public): WRONG - This is shorter, starts with "eyJhbGc..." and contains "anon" in the JWT +# ✅ service_role (secret): CORRECT - This is longer and contains "service_role" in the JWT +# +# The service_role key is typically much longer than the anon key. +# If you see errors like "Failed to save" or "Permission denied", you're using the wrong key! +# +# On the Supabase dashboard, it's labeled as "service_role" under "Project API keys" +SUPABASE_SERVICE_KEY= + +# Optional: Set log level for debugging +LOGFIRE_TOKEN= +LOG_LEVEL=INFO + +# Service Ports Configuration +# These ports are used for external access to the services +HOST=localhost +ARCHON_SERVER_PORT=8181 +ARCHON_MCP_PORT=8051 +ARCHON_AGENTS_PORT=8052 +ARCHON_UI_PORT=3737 +ARCHON_DOCS_PORT=3838 + +# Embedding Configuration +# Dimensions for embedding vectors (1536 for OpenAI text-embedding-3-small) +EMBEDDING_DIMENSIONS=1536 + +# NOTE: All other configuration has been moved to database management! +# Run the credentials_setup.sql file in your Supabase SQL editor to set up the credentials table. +# Then use the Settings page in the web UI to manage: +# - OPENAI_API_KEY (encrypted) +# - MODEL_CHOICE +# - TRANSPORT settings +# - RAG strategy flags (USE_CONTEXTUAL_EMBEDDINGS, USE_HYBRID_SEARCH, etc.) +# - Crawler settings: +# * CRAWL_MAX_CONCURRENT (default: 10) - Max concurrent pages per crawl operation +# * CRAWL_BATCH_SIZE (default: 50) - URLs processed per batch +# * MEMORY_THRESHOLD_PERCENT (default: 80) - Memory % before throttling +# * DISPATCHER_CHECK_INTERVAL (default: 0.5) - Memory check interval in seconds + + +================================================ +FILE: archon-ui-main/README.md +================================================ +# Archon UI - Knowledge Engine Web Interface + +A modern React-based web interface for the Archon Knowledge Engine MCP Server. Built with TypeScript, Vite, and Tailwind CSS. + +## 🎨 UI Overview + +Archon UI provides a comprehensive dashboard for managing your AI's knowledge base: + +![UI Architecture](https://via.placeholder.com/800x400?text=Archon+UI+Architecture) + +### Key Features + +- **📊 MCP Dashboard**: Monitor and control the MCP server +- **⚙️ Settings Management**: Configure credentials and RAG strategies +- **🕷️ Web Crawling**: Crawl documentation sites and build knowledge base +- **📚 Knowledge Management**: Browse, search, and organize knowledge items +- **💬 Interactive Chat**: Test RAG queries with real-time responses +- **📈 Real-time Updates**: WebSocket-based live updates across the UI + +## 🏗️ Architecture + +### Technology Stack + +- **React 18.3**: Modern React with hooks and functional components +- **TypeScript**: Full type safety and IntelliSense support +- **Vite**: Fast build tool and dev server +- **Tailwind CSS**: Utility-first styling +- **Framer Motion**: Smooth animations and transitions +- **Lucide Icons**: Beautiful and consistent iconography +- **React Router**: Client-side routing + +### Project Structure + +``` +archon-ui-main/ +├── src/ +│ ├── components/ # Reusable UI components +│ │ ├── ui/ # Base UI components (Button, Card, etc.) +│ │ ├── layouts/ # Layout components (Sidebar, Header) +│ │ └── animations/ # Animation components +│ ├── pages/ # Page components +│ │ ├── MCPPage.tsx # MCP Dashboard +│ │ ├── Settings.tsx # Settings page +│ │ ├── Crawl.tsx # Web crawling interface +│ │ ├── KnowledgeBase.tsx # Knowledge management +│ │ └── Chat.tsx # RAG chat interface +│ ├── services/ # API and service layers +│ │ ├── api.ts # Base API configuration +│ │ ├── mcpService.ts # MCP server communication +│ │ └── chatService.ts # Chat/RAG service +│ ├── contexts/ # React contexts +│ │ └── ToastContext.tsx # Toast notifications +│ ├── hooks/ # Custom React hooks +│ │ └── useStaggeredEntrance.ts # Animation hook +│ ├── types/ # TypeScript type definitions +│ └── lib/ # Utility functions +├── public/ # Static assets +└── test/ # Test files +``` + +## 📄 Pages Documentation + +### 1. MCP Dashboard (`/mcp`) + +The central control panel for the MCP server. + +**Components:** +- **Server Control Panel**: Start/stop server, view status, select transport mode +- **Server Logs Viewer**: Real-time log streaming with auto-scroll +- **Available Tools Table**: Dynamic tool discovery and documentation +- **MCP Test Panel**: Interactive tool testing interface + +**Features:** +- Dual transport support (SSE/stdio) +- Real-time status polling (5-second intervals) +- WebSocket-based log streaming +- Copy-to-clipboard configuration +- Tool parameter validation + +### 2. Settings (`/settings`) + +Comprehensive configuration management. + +**Sections:** +- **Credentials**: + - OpenAI API key (encrypted storage) + - Supabase connection details + - MCP server configuration +- **RAG Strategies**: + - Contextual Embeddings toggle + - Hybrid Search toggle + - Agentic RAG (code extraction) toggle + - Reranking toggle + +**Features:** +- Secure credential storage with encryption +- Real-time validation +- Toast notifications for actions +- Default value management + +### 3. Web Crawling (`/crawl`) + +Interface for crawling documentation sites. + +**Components:** +- **URL Input**: Smart URL validation +- **Crawl Options**: Max depth, concurrent sessions +- **Progress Monitoring**: Real-time crawl status +- **Results Summary**: Pages crawled, chunks stored + +**Features:** +- Intelligent URL type detection +- Sitemap support +- Recursive crawling +- Batch processing + +### 4. Knowledge Base (`/knowledge`) + +Browse and manage your knowledge items. + +**Components:** +- **Knowledge Grid**: Card-based knowledge display +- **Search/Filter**: Search by title, type, tags +- **Knowledge Details**: View full item details +- **Actions**: Delete, refresh, organize + +**Features:** +- Pagination support +- Real-time updates via WebSocket +- Type-based filtering (technical/business) +- Metadata display + +### 5. RAG Chat (`/chat`) + +Interactive chat interface for testing RAG queries. + +**Components:** +- **Chat Messages**: Threaded conversation view +- **Input Area**: Query input with source selection +- **Results Display**: Formatted RAG results +- **Source Selector**: Filter by knowledge source + +**Features:** +- Real-time streaming responses +- Source attribution +- Markdown rendering +- Copy functionality + +## 🧩 Component Library + +### Base UI Components + +#### Button +```tsx + +``` + +#### Card +```tsx + +

Card Title

+

Card content

+
+``` + +#### LoadingSpinner +```tsx + +``` + +### Layout Components + +#### Sidebar +- Collapsible navigation +- Active route highlighting +- Icon + text navigation items +- Responsive design + +#### Header +- Dark mode toggle +- User menu +- Breadcrumb navigation + +### Animation Components + +#### PageTransition +Wraps pages with smooth fade/slide animations: +```tsx + + + +``` + +## 🔌 Services + +### mcpService +Handles all MCP server communication: +- `startServer()`: Start the MCP server +- `stopServer()`: Stop the MCP server +- `getStatus()`: Get current server status +- `streamLogs()`: WebSocket log streaming +- `getAvailableTools()`: Fetch MCP tools + +### api +Base API configuration with: +- Automatic error handling +- Request/response interceptors +- Base URL configuration +- TypeScript generics + +### chatService +RAG query interface: +- `sendMessage()`: Send RAG query +- `streamResponse()`: Stream responses +- `getSources()`: Get available sources + +## 🎨 Styling + +### Tailwind Configuration +- Custom color palette +- Dark mode support +- Custom animations +- Responsive breakpoints + +### Theme Variables +```css +--primary: Blue accent colors +--secondary: Gray/neutral colors +--success: Green indicators +--warning: Orange indicators +--error: Red indicators +``` + +## 🚀 Development + +### Setup +```bash +# Install dependencies +npm install + +# Start dev server +npm run dev + +# Build for production +npm run build + +# Run tests +npm test +``` + +### Environment Variables +```env +VITE_API_URL=http://localhost:8080 +``` + +### Hot Module Replacement +Vite provides instant HMR for: +- React components +- CSS modules +- TypeScript files + +## 🧪 Testing + +### Unit Tests +- Component testing with React Testing Library +- Service mocking with MSW +- Hook testing with @testing-library/react-hooks + +### Integration Tests +- Page-level testing +- API integration tests +- WebSocket testing + +## 📦 Build & Deployment + +### Docker Support +```dockerfile +FROM node:18-alpine +WORKDIR /app +COPY package*.json ./ +RUN npm ci +COPY . . +RUN npm run build +EXPOSE 5173 +CMD ["npm", "run", "preview"] +``` + +### Production Optimization +- Code splitting by route +- Lazy loading for pages +- Image optimization +- Bundle size analysis + +## 🔧 Configuration Files + +### vite.config.ts +- Path aliases +- Build optimization +- Development server config + +### tsconfig.json +- Strict type checking +- Path mappings +- Compiler options + +### tailwind.config.js +- Custom theme +- Plugin configuration +- Purge settings + +## 🤝 Contributing + +### Code Style +- ESLint configuration +- Prettier formatting +- TypeScript strict mode +- Component naming conventions + +### Git Workflow +- Feature branches +- Conventional commits +- PR templates +- Code review process + + + +================================================ +FILE: archon-ui-main/Dockerfile +================================================ +# Simple Vite dev server setup +FROM node:18-alpine + +WORKDIR /app + +# Install system dependencies needed for some npm packages +RUN apk add --no-cache python3 make g++ git curl + +# Copy package files +COPY package*.json ./ + +# Install dependencies including dev dependencies for testing +RUN npm ci + +# Create coverage directory with proper permissions +RUN mkdir -p /app/coverage && chmod 777 /app/coverage + +# Copy source code +COPY . . + +# Expose Vite's default port +EXPOSE 5173 + +# Start Vite dev server with host binding for Docker +CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"] + + + +================================================ +FILE: archon-ui-main/index.html +================================================ + + + + + + + Archon - Knowledge Engine + + +
+ + + + + + +================================================ +FILE: archon-ui-main/package.json +================================================ +{ + "name": "archon-ui", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "dev": "npx vite", + "build": "npx vite build", + "lint": "eslint . --ext .js,.jsx,.ts,.tsx", + "preview": "npx vite preview", + "test": "vitest", + "test:ui": "vitest --ui", + "test:coverage": "npm run test:coverage:run && npm run test:coverage:summary", + "test:coverage:run": "vitest run --coverage --reporter=dot --reporter=json", + "test:coverage:stream": "vitest run --coverage --reporter=default --reporter=json --bail=false || true", + "test:coverage:summary": "echo '\\n📊 ARCHON TEST & COVERAGE SUMMARY\\n═══════════════════════════════════════\\n' && node -e \"try { const data = JSON.parse(require('fs').readFileSync('coverage/test-results.json', 'utf8')); const passed = data.numPassedTests || 0; const failed = data.numFailedTests || 0; const total = data.numTotalTests || 0; const suites = data.numTotalTestSuites || 0; console.log('Test Suites: ' + (failed > 0 ? '\\x1b[31m' + failed + ' failed\\x1b[0m, ' : '') + '\\x1b[32m' + (suites - failed) + ' passed\\x1b[0m, ' + suites + ' total'); console.log('Tests: ' + (failed > 0 ? '\\x1b[31m' + failed + ' failed\\x1b[0m, ' : '') + '\\x1b[32m' + passed + ' passed\\x1b[0m, ' + total + ' total'); console.log('\\n✨ Results saved to coverage/test-results.json'); } catch(e) { console.log('⚠️ No test results found. Run tests first!'); }\" || true", + "test:coverage:force": "vitest run --coverage --passWithNoTests || true", + "seed:projects": "node --loader ts-node/esm ../scripts/seed-project-data.ts" + }, + "dependencies": { + "@milkdown/crepe": "^7.5.0", + "@milkdown/kit": "^7.5.0", + "@milkdown/plugin-history": "^7.5.0", + "@milkdown/preset-commonmark": "^7.5.0", + "@xyflow/react": "^12.3.0", + "clsx": "latest", + "date-fns": "^4.1.0", + "fractional-indexing": "^3.2.0", + "framer-motion": "^11.5.4", + "lucide-react": "^0.441.0", + "prismjs": "^1.30.0", + "react": "^18.3.1", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.26.2", + "socket.io-client": "^4.8.1", + "tailwind-merge": "latest", + "zod": "^3.25.46" + }, + "devDependencies": { + "@testing-library/jest-dom": "^6.4.6", + "@testing-library/react": "^14.3.1", + "@testing-library/user-event": "^14.5.2", + "@types/node": "^20.19.0", + "@types/react": "^18.3.1", + "@types/react-dom": "^18.3.1", + "@typescript-eslint/eslint-plugin": "^5.54.0", + "@typescript-eslint/parser": "^5.54.0", + "@vitejs/plugin-react": "^4.2.1", + "@vitest/coverage-v8": "^1.6.0", + "@vitest/ui": "^1.6.0", + "autoprefixer": "latest", + "eslint": "^8.50.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.1", + "jsdom": "^24.1.0", + "postcss": "latest", + "tailwindcss": "3.4.17", + "ts-node": "^10.9.1", + "typescript": "^5.5.4", + "vite": "^5.2.0", + "vitest": "^1.6.0" + } +} + + + +================================================ +FILE: archon-ui-main/postcss.config.js +================================================ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} + + + +================================================ +FILE: archon-ui-main/tailwind.config.js +================================================ +module.exports = {content: [ + './index.html', + './src/**/*.{js,ts,jsx,tsx}' +], + darkMode: "selector", + theme: { + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px", + }, + }, + extend: { + colors: { + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + keyframes: { + "caret-blink": { + "0%,70%,100%": { opacity: "1" }, + "20%,50%": { opacity: "0" }, + }, + "accordion-down": { + from: { height: 0 }, + to: { height: "var(--radix-accordion-content-height)" }, + }, + "accordion-up": { + from: { height: "var(--radix-accordion-content-height)" }, + to: { height: 0 }, + }, + "shimmer": { + "100%": { transform: "translateX(100%)" }, + }, + }, + animation: { + "accordion-down": "accordion-down 0.2s ease-out", + "accordion-up": "accordion-up 0.2s ease-out", + "caret-blink": "caret-blink 1.25s ease-out infinite", + "shimmer": "shimmer 2s infinite", + }, + }, + }, +} + + +================================================ +FILE: archon-ui-main/tsconfig.json +================================================ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, +"paths": { "@/*": ["./src/*"] } + }, + "include": ["src", "test"], + "references": [{ "path": "./tsconfig.node.json" }] +} + + + +================================================ +FILE: archon-ui-main/tsconfig.node.json +================================================ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "strict": true + }, + "include": ["vite.config.ts"] +} + + + +================================================ +FILE: archon-ui-main/vite.config.ts +================================================ +/// +import path from "path"; +import { defineConfig, loadEnv } from "vite"; +import react from "@vitejs/plugin-react"; +import { exec } from 'child_process'; +import { readFile } from 'fs/promises'; +import { existsSync, mkdirSync } from 'fs'; +import type { ConfigEnv, UserConfig } from 'vite'; + +// https://vitejs.dev/config/ +export default defineConfig(({ mode }: ConfigEnv): UserConfig => { + // Load environment variables + const env = loadEnv(mode, process.cwd(), ''); + + // Get host and port from environment variables or use defaults + // For internal Docker communication, use the service name + // For external access, use the HOST from environment + const isDocker = process.env.DOCKER_ENV === 'true' || !!process.env.HOSTNAME; + const internalHost = 'archon-server'; // Docker service name for internal communication + const externalHost = process.env.HOST || 'localhost'; // Host for external access + const host = isDocker ? internalHost : externalHost; + const port = process.env.ARCHON_SERVER_PORT || env.ARCHON_SERVER_PORT || '8181'; + + return { + plugins: [ + react(), + // Custom plugin to add test endpoint + { + name: 'test-runner', + configureServer(server) { + // Serve coverage directory statically + server.middlewares.use(async (req, res, next) => { + if (req.url?.startsWith('/coverage/')) { + const filePath = path.join(process.cwd(), req.url); + console.log('[VITE] Serving coverage file:', filePath); + try { + const data = await readFile(filePath); + const contentType = req.url.endsWith('.json') ? 'application/json' : + req.url.endsWith('.html') ? 'text/html' : 'text/plain'; + res.setHeader('Content-Type', contentType); + res.end(data); + } catch (err) { + console.log('[VITE] Coverage file not found:', filePath); + res.statusCode = 404; + res.end('Not found'); + } + } else { + next(); + } + }); + + // Test execution endpoint (basic tests) + server.middlewares.use('/api/run-tests', (req: any, res: any) => { + if (req.method !== 'POST') { + res.statusCode = 405; + res.end('Method not allowed'); + return; + } + + res.writeHead(200, { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'Content-Type', + }); + + // Run vitest with proper configuration (includes JSON reporter) + const testProcess = exec('npm run test -- --run', { + cwd: process.cwd() + }); + + testProcess.stdout?.on('data', (data) => { + const text = data.toString(); + // Split by newlines but preserve empty lines for better formatting + const lines = text.split('\n'); + + lines.forEach((line: string) => { + // Send all lines including empty ones for proper formatting + res.write(`data: ${JSON.stringify({ type: 'output', message: line, timestamp: new Date().toISOString() })}\n\n`); + }); + + // Flush the response to ensure immediate delivery + if (res.flushHeaders) { + res.flushHeaders(); + } + }); + + testProcess.stderr?.on('data', (data) => { + const lines = data.toString().split('\n').filter((line: string) => line.trim()); + lines.forEach((line: string) => { + // Strip ANSI escape codes + const cleanLine = line.replace(/\\x1b\[[0-9;]*m/g, ''); + res.write(`data: ${JSON.stringify({ type: 'output', message: cleanLine, timestamp: new Date().toISOString() })}\n\n`); + }); + }); + + testProcess.on('close', (code) => { + res.write(`data: ${JSON.stringify({ + type: 'completed', + exit_code: code, + status: code === 0 ? 'completed' : 'failed', + message: code === 0 ? 'Tests completed and results generated!' : 'Tests failed', + timestamp: new Date().toISOString() + })}\n\n`); + res.end(); + }); + + testProcess.on('error', (error) => { + res.write(`data: ${JSON.stringify({ + type: 'error', + message: error.message, + timestamp: new Date().toISOString() + })}\n\n`); + res.end(); + }); + + req.on('close', () => { + testProcess.kill(); + }); + }); + + // Test execution with coverage endpoint + server.middlewares.use('/api/run-tests-with-coverage', (req: any, res: any) => { + if (req.method !== 'POST') { + res.statusCode = 405; + res.end('Method not allowed'); + return; + } + + res.writeHead(200, { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'Content-Type', + }); + + // Run vitest with coverage using the proper script (now includes both default and JSON reporters) + // Add CI=true to get cleaner output without HTML dumps + // Override the reporter to use verbose for better streaming output + // When running in Docker, we need to ensure the test results directory exists + const testResultsDir = path.join(process.cwd(), 'public', 'test-results'); + if (!existsSync(testResultsDir)) { + mkdirSync(testResultsDir, { recursive: true }); + } + + const testProcess = exec('npm run test:coverage:stream', { + cwd: process.cwd(), + env: { + ...process.env, + FORCE_COLOR: '1', + CI: 'true', + NODE_ENV: 'test' + } // Enable color output and CI mode for cleaner output + }); + + testProcess.stdout?.on('data', (data) => { + const text = data.toString(); + // Split by newlines but preserve empty lines for better formatting + const lines = text.split('\n'); + + lines.forEach((line: string) => { + // Strip ANSI escape codes to get clean text + const cleanLine = line.replace(/\\x1b\[[0-9;]*m/g, ''); + + // Send all lines for verbose reporter output + res.write(`data: ${JSON.stringify({ type: 'output', message: cleanLine, timestamp: new Date().toISOString() })}\n\n`); + }); + + // Flush the response to ensure immediate delivery + if (res.flushHeaders) { + res.flushHeaders(); + } + }); + + testProcess.stderr?.on('data', (data) => { + const lines = data.toString().split('\n').filter((line: string) => line.trim()); + lines.forEach((line: string) => { + // Strip ANSI escape codes + const cleanLine = line.replace(/\\x1b\[[0-9;]*m/g, ''); + res.write(`data: ${JSON.stringify({ type: 'output', message: cleanLine, timestamp: new Date().toISOString() })}\n\n`); + }); + }); + + testProcess.on('close', (code) => { + res.write(`data: ${JSON.stringify({ + type: 'completed', + exit_code: code, + status: code === 0 ? 'completed' : 'failed', + message: code === 0 ? 'Tests completed with coverage and results generated!' : 'Tests failed', + timestamp: new Date().toISOString() + })}\n\n`); + res.end(); + }); + + testProcess.on('error', (error) => { + res.write(`data: ${JSON.stringify({ + type: 'error', + message: error.message, + timestamp: new Date().toISOString() + })}\n\n`); + res.end(); + }); + + req.on('close', () => { + testProcess.kill(); + }); + }); + + // Coverage generation endpoint + server.middlewares.use('/api/generate-coverage', (req: any, res: any) => { + if (req.method !== 'POST') { + res.statusCode = 405; + res.end('Method not allowed'); + return; + } + + res.writeHead(200, { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'Content-Type', + }); + + res.write(`data: ${JSON.stringify({ + type: 'status', + message: 'Starting coverage generation...', + timestamp: new Date().toISOString() + })}\n\n`); + + // Run coverage generation + const coverageProcess = exec('npm run test:coverage', { + cwd: process.cwd() + }); + + coverageProcess.stdout?.on('data', (data) => { + const lines = data.toString().split('\n').filter((line: string) => line.trim()); + lines.forEach((line: string) => { + res.write(`data: ${JSON.stringify({ type: 'output', message: line, timestamp: new Date().toISOString() })}\n\n`); + }); + }); + + coverageProcess.stderr?.on('data', (data) => { + const lines = data.toString().split('\n').filter((line: string) => line.trim()); + lines.forEach((line: string) => { + res.write(`data: ${JSON.stringify({ type: 'output', message: line, timestamp: new Date().toISOString() })}\n\n`); + }); + }); + + coverageProcess.on('close', (code) => { + res.write(`data: ${JSON.stringify({ + type: 'completed', + exit_code: code, + status: code === 0 ? 'completed' : 'failed', + message: code === 0 ? 'Coverage report generated successfully!' : 'Coverage generation failed', + timestamp: new Date().toISOString() + })}\n\n`); + res.end(); + }); + + coverageProcess.on('error', (error) => { + res.write(`data: ${JSON.stringify({ + type: 'error', + message: error.message, + timestamp: new Date().toISOString() + })}\n\n`); + res.end(); + }); + + req.on('close', () => { + coverageProcess.kill(); + }); + }); + } + } + ], + server: { + host: '0.0.0.0', // Listen on all network interfaces with explicit IP + port: 5173, // Match the port expected in Docker + strictPort: true, // Exit if port is in use + proxy: { + '/api': { + target: `http://${host}:${port}`, + changeOrigin: true, + secure: false, + ws: true, + configure: (proxy, options) => { + proxy.on('error', (err, req, res) => { + console.log('🚨 [VITE PROXY ERROR]:', err.message); + console.log('🚨 [VITE PROXY ERROR] Target:', `http://${host}:${port}`); + console.log('🚨 [VITE PROXY ERROR] Request:', req.url); + }); + proxy.on('proxyReq', (proxyReq, req, res) => { + console.log('🔄 [VITE PROXY] Forwarding:', req.method, req.url, 'to', `http://${host}:${port}${req.url}`); + }); + } + }, + // Socket.IO specific proxy configuration + '/socket.io': { + target: `http://${host}:${port}`, + changeOrigin: true, + ws: true + } + }, + }, + define: { + 'import.meta.env.VITE_HOST': JSON.stringify(host), + 'import.meta.env.VITE_PORT': JSON.stringify(port), + }, + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, + test: { + globals: true, + environment: 'jsdom', + setupFiles: './test/setup.ts', + css: true, + exclude: [ + '**/node_modules/**', + '**/dist/**', + '**/cypress/**', + '**/.{idea,git,cache,output,temp}/**', + '**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.*', + '**/*.test.{ts,tsx}', + ], + env: { + VITE_HOST: host, + VITE_PORT: port, + }, + coverage: { + provider: 'v8', + reporter: ['text', 'json', 'html'], + exclude: [ + 'node_modules/', + 'test/', + '**/*.d.ts', + '**/*.config.*', + '**/mockData.ts', + '**/*.test.{ts,tsx}', + ], + } + } + }; +}); + + + +================================================ +FILE: archon-ui-main/vitest.config.ts +================================================ +/// +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import path from 'path' + +export default defineConfig({ + plugins: [react()], + test: { + globals: true, + environment: 'jsdom', + setupFiles: './test/setup.ts', + include: [ + 'test/components.test.tsx', + 'test/pages.test.tsx', + 'test/user_flows.test.tsx', + 'test/errors.test.tsx', + 'test/services/projectService.test.ts', + 'test/components/project-tasks/DocsTab.integration.test.tsx', + 'test/config/api.test.ts' + ], + exclude: ['node_modules', 'dist', '.git', '.cache', 'test.backup', '*.backup/**', 'test-backups'], + reporters: ['dot', 'json'], + outputFile: { + json: './public/test-results/test-results.json' + }, + testTimeout: 10000, // 10 seconds timeout + hookTimeout: 10000, // 10 seconds for setup/teardown + coverage: { + provider: 'v8', + reporter: [ + 'text', + 'text-summary', + 'html', + 'json', + 'json-summary', + 'lcov' + ], + reportsDirectory: './public/test-results/coverage', + clean: false, // Don't clean the directory as it may be in use + reportOnFailure: true, // Generate coverage reports even when tests fail + exclude: [ + 'node_modules/', + 'test/', + '**/*.d.ts', + '**/*.config.*', + '**/mockData.ts', + '**/*.test.{ts,tsx}', + 'src/env.d.ts', + 'coverage/**', + 'dist/**', + 'public/**', + '**/*.stories.*', + '**/*.story.*', + ], + include: [ + 'src/**/*.{ts,tsx}', + ], + thresholds: {} + }, + }, + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + }, + }, +}) + + +================================================ +FILE: archon-ui-main/.dockerignore +================================================ +# Dependencies +node_modules +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Build output +dist +build + +# Environment variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# IDE and editor files +.vscode +.idea +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Git +.git +.gitignore + +# Docker +Dockerfile +docker-compose.yml +.dockerignore + +# Tests +coverage +test-results + +# Documentation +README.md +*.md + + +================================================ +FILE: archon-ui-main/.eslintrc.cjs +================================================ +module.exports = { + root: true, + env: { browser: true, es2020: true, node: true }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parser: '@typescript-eslint/parser', + plugins: ['react-refresh'], + rules: { + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + '@typescript-eslint/no-unused-vars': ['warn', { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + ignoreRestSiblings: true + }], + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/ban-types': 'off', + '@typescript-eslint/no-non-null-assertion': 'warn', + '@typescript-eslint/no-inferrable-types': 'off', + 'react-hooks/exhaustive-deps': 'warn', + 'no-case-declarations': 'off', + 'no-constant-condition': 'warn', + 'prefer-const': 'warn', + 'no-undef': 'off', + }, +} + + + +================================================ +FILE: archon-ui-main/__mocks__/lucide-react.tsx +================================================ +import React from 'react' +import { vi } from 'vitest' + +const createMockIcon = (name: string) => { + const MockIcon = React.forwardRef(({ className, ...props }: any, ref: any) => ( + + {name} + + )) + MockIcon.displayName = name + return MockIcon +} + +// Export all icons used in the app +export const Settings = createMockIcon('Settings') +export const Check = createMockIcon('Check') +export const CheckCircle = createMockIcon('CheckCircle') +export const X = createMockIcon('X') +export const XCircle = createMockIcon('XCircle') +export const Eye = createMockIcon('Eye') +export const EyeOff = createMockIcon('EyeOff') +export const Save = createMockIcon('Save') +export const Loader = createMockIcon('Loader') +export const Loader2 = createMockIcon('Loader2') +export const RefreshCw = createMockIcon('RefreshCw') +export const Play = createMockIcon('Play') +export const Pause = createMockIcon('Pause') +export const Square = createMockIcon('Square') +export const FileText = createMockIcon('FileText') +export const Download = createMockIcon('Download') +export const Upload = createMockIcon('Upload') +export const ChevronDown = createMockIcon('ChevronDown') +export const ChevronUp = createMockIcon('ChevronUp') +export const ChevronLeft = createMockIcon('ChevronLeft') +export const ChevronRight = createMockIcon('ChevronRight') +export const Plus = createMockIcon('Plus') +export const Minus = createMockIcon('Minus') +export const Edit = createMockIcon('Edit') +export const Edit2 = createMockIcon('Edit2') +export const Edit3 = createMockIcon('Edit3') +export const Trash = createMockIcon('Trash') +export const Trash2 = createMockIcon('Trash2') +export const User = createMockIcon('User') +export const Users = createMockIcon('Users') +export const Bot = createMockIcon('Bot') +export const Database = createMockIcon('Database') +export const Server = createMockIcon('Server') +export const Globe = createMockIcon('Globe') +export const Search = createMockIcon('Search') +export const Filter = createMockIcon('Filter') +export const Copy = createMockIcon('Copy') +export const ExternalLink = createMockIcon('ExternalLink') +export const Info = createMockIcon('Info') +export const AlertCircle = createMockIcon('AlertCircle') +export const AlertTriangle = createMockIcon('AlertTriangle') +export const Zap = createMockIcon('Zap') +export const Code = createMockIcon('Code') +export const Terminal = createMockIcon('Terminal') +export const Book = createMockIcon('Book') +export const BookOpen = createMockIcon('BookOpen') +export const Folder = createMockIcon('Folder') +export const FolderOpen = createMockIcon('FolderOpen') +export const File = createMockIcon('File') +export const Hash = createMockIcon('Hash') +export const Tag = createMockIcon('Tag') +export const Clock = createMockIcon('Clock') +export const Calendar = createMockIcon('Calendar') +export const MapPin = createMockIcon('MapPin') +export const Link = createMockIcon('Link') +export const Mail = createMockIcon('Mail') +export const Phone = createMockIcon('Phone') +export const Home = createMockIcon('Home') +export const Menu = createMockIcon('Menu') +export const MoreHorizontal = createMockIcon('MoreHorizontal') +export const MoreVertical = createMockIcon('MoreVertical') +export const Refresh = createMockIcon('Refresh') +export const RotateCcw = createMockIcon('RotateCcw') +export const RotateCw = createMockIcon('RotateCw') +export const Sun = createMockIcon('Sun') +export const Moon = createMockIcon('Moon') +export const Monitor = createMockIcon('Monitor') +export const Wifi = createMockIcon('Wifi') +export const WifiOff = createMockIcon('WifiOff') +export const Volume2 = createMockIcon('Volume2') +export const VolumeX = createMockIcon('VolumeX') +export const BarChart = createMockIcon('BarChart') +export const PieChart = createMockIcon('PieChart') +export const TrendingUp = createMockIcon('TrendingUp') +export const TrendingDown = createMockIcon('TrendingDown') +export const ArrowUp = createMockIcon('ArrowUp') +export const ArrowDown = createMockIcon('ArrowDown') +export const ArrowLeft = createMockIcon('ArrowLeft') +export const ArrowRight = createMockIcon('ArrowRight') +export const Send = createMockIcon('Send') +export const MessageSquare = createMockIcon('MessageSquare') +export const MessageCircle = createMockIcon('MessageCircle') +export const Heart = createMockIcon('Heart') +export const Star = createMockIcon('Star') +export const Bookmark = createMockIcon('Bookmark') +export const Share = createMockIcon('Share') +export const Share2 = createMockIcon('Share2') +export const Maximize = createMockIcon('Maximize') +export const Minimize = createMockIcon('Minimize') +export const Expand = createMockIcon('Expand') +export const Shrink = createMockIcon('Shrink') +export const Move = createMockIcon('Move') +export const Shuffle = createMockIcon('Shuffle') +export const Repeat = createMockIcon('Repeat') +export const StopCircle = createMockIcon('StopCircle') +export const SkipBack = createMockIcon('SkipBack') +export const SkipForward = createMockIcon('SkipForward') +export const FastForward = createMockIcon('FastForward') +export const Rewind = createMockIcon('Rewind') +export const Camera = createMockIcon('Camera') +export const Image = createMockIcon('Image') +export const Video = createMockIcon('Video') +export const Mic = createMockIcon('Mic') +export const MicOff = createMockIcon('MicOff') +export const Headphones = createMockIcon('Headphones') +export const Speaker = createMockIcon('Speaker') +export const Bell = createMockIcon('Bell') +export const BellOff = createMockIcon('BellOff') +export const Shield = createMockIcon('Shield') +export const ShieldCheck = createMockIcon('ShieldCheck') +export const ShieldAlert = createMockIcon('ShieldAlert') +export const Key = createMockIcon('Key') +export const Lock = createMockIcon('Lock') +export const Unlock = createMockIcon('Unlock') +export const LogIn = createMockIcon('LogIn') +export const LogOut = createMockIcon('LogOut') +export const UserPlus = createMockIcon('UserPlus') +export const UserMinus = createMockIcon('UserMinus') +export const UserCheck = createMockIcon('UserCheck') +export const UserX = createMockIcon('UserX') +export const Package = createMockIcon('Package') +export const Package2 = createMockIcon('Package2') +export const ShoppingCart = createMockIcon('ShoppingCart') +export const ShoppingBag = createMockIcon('ShoppingBag') +export const CreditCard = createMockIcon('CreditCard') +export const DollarSign = createMockIcon('DollarSign') +export const Percent = createMockIcon('Percent') +export const Activity = createMockIcon('Activity') +export const Cpu = createMockIcon('Cpu') +export const HardDrive = createMockIcon('HardDrive') +export const MemoryStick = createMockIcon('MemoryStick') +export const Smartphone = createMockIcon('Smartphone') +export const Tablet = createMockIcon('Tablet') +export const Laptop = createMockIcon('Laptop') +export const Monitor2 = createMockIcon('Monitor2') +export const Tv = createMockIcon('Tv') +export const Watch = createMockIcon('Watch') +export const Gamepad2 = createMockIcon('Gamepad2') +export const Mouse = createMockIcon('Mouse') +export const Keyboard = createMockIcon('Keyboard') +export const Printer = createMockIcon('Printer') +export const Scanner = createMockIcon('Scanner') +export const Webcam = createMockIcon('Webcam') +export const Bluetooth = createMockIcon('Bluetooth') +export const Usb = createMockIcon('Usb') +export const Zap2 = createMockIcon('Zap2') +export const Battery = createMockIcon('Battery') +export const BatteryCharging = createMockIcon('BatteryCharging') +export const Plug = createMockIcon('Plug') +export const Power = createMockIcon('Power') +export const PowerOff = createMockIcon('PowerOff') +export const BarChart2 = createMockIcon('BarChart2') +export const BarChart3 = createMockIcon('BarChart3') +export const BarChart4 = createMockIcon('BarChart4') +export const LineChart = createMockIcon('LineChart') +export const PieChart2 = createMockIcon('PieChart2') +export const Layers = createMockIcon('Layers') +export const Layers2 = createMockIcon('Layers2') +export const Layers3 = createMockIcon('Layers3') +export const Grid = createMockIcon('Grid') +export const Grid2x2 = createMockIcon('Grid2x2') +export const Grid3x3 = createMockIcon('Grid3x3') +export const List = createMockIcon('List') +export const ListChecks = createMockIcon('ListChecks') +export const ListTodo = createMockIcon('ListTodo') +export const CheckSquare = createMockIcon('CheckSquare') +export const Square2 = createMockIcon('Square2') +export const Circle = createMockIcon('Circle') +export const CircleCheck = createMockIcon('CircleCheck') +export const CircleX = createMockIcon('CircleX') +export const CircleDot = createMockIcon('CircleDot') +export const Target = createMockIcon('Target') +export const Focus = createMockIcon('Focus') +export const Crosshair = createMockIcon('Crosshair') +export const Locate = createMockIcon('Locate') +export const LocateFixed = createMockIcon('LocateFixed') +export const Navigation = createMockIcon('Navigation') +export const Navigation2 = createMockIcon('Navigation2') +export const Compass = createMockIcon('Compass') +export const Map = createMockIcon('Map') +export const TestTube = createMockIcon('TestTube') +export const FlaskConical = createMockIcon('FlaskConical') +export const Bug = createMockIcon('Bug') +export const GitBranch = createMockIcon('GitBranch') +export const GitCommit = createMockIcon('GitCommit') +export const GitMerge = createMockIcon('GitMerge') +export const GitPullRequest = createMockIcon('GitPullRequest') +export const Github = createMockIcon('Github') +export const Gitlab = createMockIcon('Gitlab') +export const Bitbucket = createMockIcon('Bitbucket') +export const Network = createMockIcon('Network') +export const GitGraph = createMockIcon('GitGraph') +export const ListFilter = createMockIcon('ListFilter') +export const CheckSquare2 = createMockIcon('CheckSquare2') +export const CircleSlash2 = createMockIcon('CircleSlash2') +export const Clock3 = createMockIcon('Clock3') +export const GitCommitHorizontal = createMockIcon('GitCommitHorizontal') +export const CalendarDays = createMockIcon('CalendarDays') +export const Sparkles = createMockIcon('Sparkles') +export const Layout = createMockIcon('Layout') +export const Table = createMockIcon('Table') +export const Columns = createMockIcon('Columns') +export const GitPullRequestDraft = createMockIcon('GitPullRequestDraft') +export const BrainCircuit = createMockIcon('BrainCircuit') +export const Wrench = createMockIcon('Wrench') +export const PlugZap = createMockIcon('PlugZap') +export const BoxIcon = createMockIcon('BoxIcon') +export const Box = createMockIcon('Box') +export const Brain = createMockIcon('Brain') +export const LinkIcon = createMockIcon('LinkIcon') +export const Sparkle = createMockIcon('Sparkle') +export const FolderTree = createMockIcon('FolderTree') +export const Lightbulb = createMockIcon('Lightbulb') +export const Rocket = createMockIcon('Rocket') +export const Building = createMockIcon('Building') +export const FileCode = createMockIcon('FileCode') +export const FileJson = createMockIcon('FileJson') +export const Braces = createMockIcon('Braces') +export const Binary = createMockIcon('Binary') +export const Palette = createMockIcon('Palette') +export const Paintbrush = createMockIcon('Paintbrush') +export const Type = createMockIcon('Type') +export const Heading = createMockIcon('Heading') +export const AlignLeft = createMockIcon('AlignLeft') +export const AlignCenter = createMockIcon('AlignCenter') +export const AlignRight = createMockIcon('AlignRight') +export const Bold = createMockIcon('Bold') +export const Italic = createMockIcon('Italic') +export const Underline = createMockIcon('Underline') +export const Strikethrough = createMockIcon('Strikethrough') +export const FileCheck = createMockIcon('FileCheck') +export const FileX = createMockIcon('FileX') +export const FilePlus = createMockIcon('FilePlus') +export const FileMinus = createMockIcon('FileMinus') +export const FolderPlus = createMockIcon('FolderPlus') +export const FolderMinus = createMockIcon('FolderMinus') +export const FolderCheck = createMockIcon('FolderCheck') +export const FolderX = createMockIcon('FolderX') +export const startMCPServer = createMockIcon('startMCPServer') +export const Pin = createMockIcon('Pin') +export const CheckCircle2 = createMockIcon('CheckCircle2') +export const Clipboard = createMockIcon('Clipboard') +export const LayoutGrid = createMockIcon('LayoutGrid') +export const Pencil = createMockIcon('Pencil') +export const MousePointer = createMockIcon('MousePointer') +export const GripVertical = createMockIcon('GripVertical') +export const History = createMockIcon('History') +export const PlusCircle = createMockIcon('PlusCircle') +export const MinusCircle = createMockIcon('MinusCircle') +export const ChevronDownIcon = createMockIcon('ChevronDownIcon') +export const FileIcon = createMockIcon('FileIcon') +export const AlertCircleIcon = createMockIcon('AlertCircleIcon') +export const Clock4 = createMockIcon('Clock4') +export const XIcon = createMockIcon('XIcon') +export const CheckIcon = createMockIcon('CheckIcon') +export const TrashIcon = createMockIcon('TrashIcon') +export const EyeIcon = createMockIcon('EyeIcon') +export const EditIcon = createMockIcon('EditIcon') +export const DownloadIcon = createMockIcon('DownloadIcon') +export const RefreshIcon = createMockIcon('RefreshIcon') +export const SearchIcon = createMockIcon('SearchIcon') +export const FilterIcon = createMockIcon('FilterIcon') +export const PlusIcon = createMockIcon('PlusIcon') +export const FolderIcon = createMockIcon('FolderIcon') +export const FileTextIcon = createMockIcon('FileTextIcon') +export const BookOpenIcon = createMockIcon('BookOpenIcon') +export const DatabaseIcon = createMockIcon('DatabaseIcon') +export const GlobeIcon = createMockIcon('GlobeIcon') +export const TagIcon = createMockIcon('TagIcon') +export const CalendarIcon = createMockIcon('CalendarIcon') +export const ClockIcon = createMockIcon('ClockIcon') +export const UserIcon = createMockIcon('UserIcon') +export const SettingsIcon = createMockIcon('SettingsIcon') +export const InfoIcon = createMockIcon('InfoIcon') +export const WarningIcon = createMockIcon('WarningIcon') +export const ErrorIcon = createMockIcon('ErrorIcon') + + +================================================ +FILE: archon-ui-main/docs/socket-memoization-patterns.md +================================================ +# Socket & Memoization Patterns + +## Quick Reference + +### DO: +- ✅ Track optimistic updates to prevent double-renders +- ✅ Memoize socket event handlers with useCallback +- ✅ Check if incoming data actually differs from current state +- ✅ Use debouncing for rapid UI updates (drag & drop) +- ✅ Clean up socket listeners in useEffect cleanup + +### DON'T: +- ❌ Update state without checking if data changed +- ❌ Create new handler functions on every render +- ❌ Apply server updates that match pending optimistic updates +- ❌ Forget to handle the "modal open" edge case + +## Pattern Examples + +### Optimistic Update Pattern + +```typescript +import { useOptimisticUpdates } from '../../hooks/useOptimisticUpdates'; + +const MyComponent = () => { + const { addPendingUpdate, isPendingUpdate } = useOptimisticUpdates(); + + const handleLocalUpdate = (task: Task) => { + // Track the optimistic update + addPendingUpdate({ + id: task.id, + timestamp: Date.now(), + data: task, + operation: 'update' + }); + + // Update local state immediately + setTasks(prev => prev.map(t => t.id === task.id ? task : t)); + + // Persist to server + api.updateTask(task); + }; + + const handleServerUpdate = useCallback((task: Task) => { + // Skip if this is our own update echoing back + if (isPendingUpdate(task.id, task)) { + console.log('Skipping own optimistic update'); + return; + } + + // Apply server update + setTasks(prev => prev.map(t => t.id === task.id ? task : t)); + }, [isPendingUpdate]); +}; +``` + +### Socket Handler Pattern + +```typescript +import { useSocketSubscription } from '../../hooks/useSocketSubscription'; + +const MyComponent = () => { + // Option 1: Using the hook + useSocketSubscription( + socketService, + 'data_updated', + (data) => { + console.log('Data updated:', data); + // Handle update + }, + [/* dependencies */] + ); + + // Option 2: Manual memoization + const handleUpdate = useCallback((message: any) => { + const data = message.data || message; + + setItems(prev => { + // Check if data actually changed + const existing = prev.find(item => item.id === data.id); + if (existing && JSON.stringify(existing) === JSON.stringify(data)) { + return prev; // No change, prevent re-render + } + + return prev.map(item => item.id === data.id ? data : item); + }); + }, []); + + useEffect(() => { + socketService.addMessageHandler('update', handleUpdate); + return () => { + socketService.removeMessageHandler('update', handleUpdate); + }; + }, [handleUpdate]); +}; +``` + +### Debounced Reordering Pattern + +```typescript +const useReordering = () => { + const debouncedPersist = useMemo( + () => debounce(async (items: Item[]) => { + try { + await api.updateOrder(items); + } catch (error) { + console.error('Failed to persist order:', error); + // Rollback or retry logic + } + }, 500), + [] + ); + + const handleReorder = useCallback((dragIndex: number, dropIndex: number) => { + // Update UI immediately + setItems(prev => { + const newItems = [...prev]; + const [draggedItem] = newItems.splice(dragIndex, 1); + newItems.splice(dropIndex, 0, draggedItem); + + // Update order numbers + return newItems.map((item, index) => ({ + ...item, + order: index + 1 + })); + }); + + // Persist changes (debounced) + debouncedPersist(items); + }, [items, debouncedPersist]); +}; +``` + +## WebSocket Service Configuration + +### Deduplication + +The enhanced WebSocketService now includes automatic deduplication: + +```typescript +// Configure deduplication window (default: 100ms) +socketService.setDeduplicationWindow(200); // 200ms window + +// Duplicate messages within the window are automatically filtered +``` + +### Connection Management + +```typescript +// Always check connection state before critical operations +if (socketService.isConnected()) { + socketService.send({ type: 'update', data: payload }); +} + +// Monitor connection state +socketService.addStateChangeHandler((state) => { + if (state === WebSocketState.CONNECTED) { + console.log('Connected - refresh data'); + } +}); +``` + +## Common Patterns + +### 1. State Equality Checks + +Always check if incoming data actually differs from current state: + +```typescript +// ❌ BAD - Always triggers re-render +setTasks(prev => prev.map(t => t.id === id ? newTask : t)); + +// ✅ GOOD - Only updates if changed +setTasks(prev => { + const existing = prev.find(t => t.id === id); + if (existing && deepEqual(existing, newTask)) return prev; + return prev.map(t => t.id === id ? newTask : t); +}); +``` + +### 2. Modal State Handling + +Be aware of modal state when applying updates: + +```typescript +const handleSocketUpdate = useCallback((data) => { + if (isModalOpen && editingItem?.id === data.id) { + console.warn('Update received while editing - consider skipping or merging'); + // Option 1: Skip the update + // Option 2: Merge with current edits + // Option 3: Show conflict resolution UI + } + + // Normal update flow +}, [isModalOpen, editingItem]); +``` + +### 3. Cleanup Pattern + +Always clean up socket listeners: + +```typescript +useEffect(() => { + const handlers = [ + { event: 'create', handler: handleCreate }, + { event: 'update', handler: handleUpdate }, + { event: 'delete', handler: handleDelete } + ]; + + // Add all handlers + handlers.forEach(({ event, handler }) => { + socket.addMessageHandler(event, handler); + }); + + // Cleanup + return () => { + handlers.forEach(({ event, handler }) => { + socket.removeMessageHandler(event, handler); + }); + }; +}, [handleCreate, handleUpdate, handleDelete]); +``` + +## Performance Tips + +1. **Measure First**: Use React DevTools Profiler before optimizing +2. **Batch Updates**: Group related state changes +3. **Debounce Rapid Changes**: Especially for drag & drop operations +4. **Use Stable References**: Memoize callbacks passed to child components +5. **Avoid Deep Equality Checks**: Use optimized comparison for large objects + +## Debugging + +Enable verbose logging for troubleshooting: + +```typescript +// In development +if (process.env.NODE_ENV === 'development') { + console.log('[Socket] Message received:', message); + console.log('[Socket] Deduplication result:', isDuplicate); + console.log('[Optimistic] Pending updates:', pendingUpdates); +} +``` + +## Migration Guide + +To migrate existing components: + +1. Import `useOptimisticUpdates` hook +2. Wrap socket handlers with `useCallback` +3. Add optimistic update tracking to local changes +4. Check for pending updates in socket handlers +5. Test with React DevTools Profiler + +Remember: The goal is to eliminate unnecessary re-renders while maintaining real-time synchronization across all connected clients. + + +================================================ +FILE: archon-ui-main/src/App.tsx +================================================ +import { useState, useEffect } from 'react'; +import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; +import { KnowledgeBasePage } from './pages/KnowledgeBasePage'; +import { SettingsPage } from './pages/SettingsPage'; +import { MCPPage } from './pages/MCPPage'; +import { OnboardingPage } from './pages/OnboardingPage'; +import { MainLayout } from './components/layouts/MainLayout'; +import { ThemeProvider } from './contexts/ThemeContext'; +import { ToastProvider } from './contexts/ToastContext'; +import { SettingsProvider, useSettings } from './contexts/SettingsContext'; +import { ProjectPage } from './pages/ProjectPage'; +import { DisconnectScreenOverlay } from './components/DisconnectScreenOverlay'; +import { ErrorBoundaryWithBugReport } from './components/bug-report/ErrorBoundaryWithBugReport'; +import { serverHealthService } from './services/serverHealthService'; + +const AppRoutes = () => { + const { projectsEnabled } = useSettings(); + + return ( + + } /> + } /> + } /> + } /> + {projectsEnabled ? ( + } /> + ) : ( + } /> + )} + + ); +}; + +const AppContent = () => { + const [disconnectScreenActive, setDisconnectScreenActive] = useState(false); + const [disconnectScreenDismissed, setDisconnectScreenDismissed] = useState(false); + const [disconnectScreenSettings, setDisconnectScreenSettings] = useState({ + enabled: true, + delay: 10000 + }); + + useEffect(() => { + // Load initial settings + const settings = serverHealthService.getSettings(); + setDisconnectScreenSettings(settings); + + // Stop any existing monitoring before starting new one to prevent multiple intervals + serverHealthService.stopMonitoring(); + + // Start health monitoring + serverHealthService.startMonitoring({ + onDisconnected: () => { + if (!disconnectScreenDismissed) { + setDisconnectScreenActive(true); + } + }, + onReconnected: () => { + setDisconnectScreenActive(false); + setDisconnectScreenDismissed(false); + // Refresh the page to ensure all data is fresh + window.location.reload(); + } + }); + + return () => { + serverHealthService.stopMonitoring(); + }; + }, [disconnectScreenDismissed]); + + const handleDismissDisconnectScreen = () => { + setDisconnectScreenActive(false); + setDisconnectScreenDismissed(true); + }; + + return ( + <> + + + + + + + + + + ); +}; + +export function App() { + return ( + + + + + + + + ); +} + + +================================================ +FILE: archon-ui-main/src/env.d.ts +================================================ +/// + +interface ImportMetaEnv { + readonly VITE_HOST: string; + readonly VITE_PORT: string; + // Add other environment variables here as needed +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} + + + +================================================ +FILE: archon-ui-main/src/index.css +================================================ +@tailwind base; +@tailwind components; +@tailwind utilities; +@layer base { + :root { + /* Light mode variables */ + --background: 0 0% 98%; + --foreground: 240 10% 3.9%; + --muted: 240 4.8% 95.9%; + --muted-foreground: 240 3.8% 46.1%; + --popover: 0 0% 100%; + --popover-foreground: 240 10% 3.9%; + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + --card: 0 0% 100%; + --card-foreground: 240 10% 3.9%; + --primary: 271 91% 65%; + --primary-foreground: 0 0% 100%; + --secondary: 240 4.8% 95.9%; + --secondary-foreground: 240 5.9% 10%; + --accent: 271 91% 65%; + --accent-foreground: 0 0% 100%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --ring: 240 5.9% 10%; + --radius: 0.5rem; + --purple-accent: 271 91% 65%; + --green-accent: 160 84% 39%; + --pink-accent: 330 90% 65%; + --blue-accent: 217 91% 60%; + } + .dark { + /* Dark mode variables - keep exactly as they were */ + --background: 0 0% 0%; + --foreground: 0 0% 100%; + --muted: 240 4% 16%; + --muted-foreground: 240 5% 65%; + --popover: 0 0% 0%; + --popover-foreground: 0 0% 100%; + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + --card: 0 0% 0%; + --card-foreground: 0 0% 100%; + --primary: 271 91% 65%; + --primary-foreground: 0 0% 100%; + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + --accent: 271 91% 65%; + --accent-foreground: 0 0% 100%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --ring: 240 3.7% 15.9%; + --radius: 0.5rem; + --purple-accent: 271 91% 65%; + --green-accent: 160 84% 39%; + --pink-accent: 330 90% 65%; + --blue-accent: 217 91% 60%; + } +} +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + font-feature-settings: "rlig" 1, "calt" 1; + } +} +@layer components { + .neon-grid { + @apply bg-[linear-gradient(to_right,#a855f720_1px,transparent_1px),linear-gradient(to_bottom,#a855f720_1px,transparent_1px)] bg-[size:40px_40px]; + @apply dark:bg-[linear-gradient(to_right,#a855f730_1px,transparent_1px),linear-gradient(to_bottom,#a855f730_1px,transparent_1px)]; + } + .neon-divider-h { + @apply h-[1px] w-full; + } + .neon-divider-h.purple { + @apply bg-purple-500; + } + .neon-divider-h.green { + @apply bg-emerald-500; + } + .neon-divider-h.pink { + @apply bg-pink-500; + } + .neon-divider-h.blue { + @apply bg-blue-500; + } + .neon-divider-v { + @apply w-[1px] h-full; + } + .neon-divider-v.purple { + @apply bg-purple-500; + } + .neon-divider-v.green { + @apply bg-emerald-500; + } + .neon-divider-v.pink { + @apply bg-pink-500; + } + .neon-divider-v.blue { + @apply bg-blue-500; + } + .knowledge-item-card { + @apply relative backdrop-blur-md bg-gradient-to-b from-white/10 to-black/30 border border-purple-500/30 rounded-md p-4 transition-all duration-300; + @apply before:content-[""] before:absolute before:top-0 before:left-0 before:w-full before:h-[2px] before:bg-purple-500 before:shadow-[0_0_20px_5px_rgba(168,85,247,0.7)]; + @apply after:content-[""] after:absolute after:top-0 after:left-0 after:right-0 after:h-16 after:bg-gradient-to-b after:from-purple-500/20 after:to-purple-500/5 after:rounded-t-md after:pointer-events-none; + @apply shadow-[0_10px_30px_-15px_rgba(0,0,0,0.7)]; + } + .knowledge-item-card:hover { + @apply border-purple-500/70 shadow-[0_15px_40px_-15px_rgba(0,0,0,0.9)] before:shadow-[0_0_25px_8px_rgba(168,85,247,0.8)]; + @apply translate-y-[-2px]; + } + /* Glassmorphism utility classes */ + .glass { + /* Light mode (base) styles */ + @apply backdrop-blur-md bg-gradient-to-b from-white/80 to-white/60 border border-gray-200 shadow-[0_10px_30px_-15px_rgba(0,0,0,0.1)]; + /* Dark mode overrides */ + @apply dark:bg-gradient-to-b dark:from-white/10 dark:to-black/30 dark:border-zinc-800/50 dark:shadow-[0_10px_30px_-15px_rgba(0,0,0,0.7)]; + } + .glass-purple { + /* Light mode (base) styles */ + @apply backdrop-blur-md bg-gradient-to-b from-white/80 to-white/60 border border-purple-300 shadow-[0_10px_30px_-15px_rgba(168,85,247,0.15)]; + @apply before:content-[""] before:absolute before:top-0 before:left-0 before:w-full before:h-[2px] before:bg-purple-500 before:shadow-[0_0_10px_2px_rgba(168,85,247,0.4)]; + @apply after:content-[""] after:absolute after:top-0 after:left-0 after:right-0 after:h-16 after:bg-gradient-to-b after:from-purple-100 after:to-white after:rounded-t-md after:pointer-events-none; + /* Dark mode overrides */ + @apply dark:from-white/10 dark:to-black/30 dark:border-purple-500/30 dark:shadow-[0_10px_30px_-15px_rgba(0,0,0,0.7)]; + @apply dark:before:shadow-[0_0_20px_5px_rgba(168,85,247,0.7)]; + @apply dark:after:from-purple-500/20 dark:after:to-purple-500/5; + } + .glass-green { + /* Light mode (base) styles */ + @apply backdrop-blur-md bg-gradient-to-b from-white/80 to-white/60 border border-emerald-300 shadow-[0_10px_30px_-15px_rgba(16,185,129,0.15)]; + @apply before:content-[""] before:absolute before:top-0 before:left-0 before:w-full before:h-[2px] before:bg-emerald-500 before:shadow-[0_0_10px_2px_rgba(16,185,129,0.4)]; + @apply after:content-[""] after:absolute after:top-0 after:left-0 after:right-0 after:h-16 after:bg-gradient-to-b after:from-emerald-100 after:to-white after:rounded-t-md after:pointer-events-none; + /* Dark mode overrides */ + @apply dark:from-white/10 dark:to-black/30 dark:border-emerald-500/30 dark:shadow-[0_10px_30px_-15px_rgba(0,0,0,0.7)]; + @apply dark:before:shadow-[0_0_20px_5px_rgba(16,185,129,0.7)]; + @apply dark:after:from-emerald-500/20 dark:after:to-emerald-500/5; + } + .glass-pink { + /* Light mode (base) styles */ + @apply backdrop-blur-md bg-gradient-to-b from-white/80 to-white/60 border border-pink-300 shadow-[0_10px_30px_-15px_rgba(236,72,153,0.15)]; + @apply before:content-[""] before:absolute before:top-0 before:left-0 before:w-full before:h-[2px] before:bg-pink-500 before:shadow-[0_0_10px_2px_rgba(236,72,153,0.4)]; + @apply after:content-[""] after:absolute after:top-0 after:left-0 after:right-0 after:h-16 after:bg-gradient-to-b after:from-pink-100 after:to-white after:rounded-t-md after:pointer-events-none; + /* Dark mode overrides */ + @apply dark:from-white/10 dark:to-black/30 dark:border-pink-500/30 dark:shadow-[0_10px_30px_-15px_rgba(0,0,0,0.7)]; + @apply dark:before:shadow-[0_0_20px_5px_rgba(236,72,153,0.7)]; + @apply dark:after:from-pink-500/20 dark:after:to-pink-500/5; + } + .glass-blue { + /* Light mode (base) styles */ + @apply backdrop-blur-md bg-gradient-to-b from-white/80 to-white/60 border border-blue-300 shadow-[0_10px_30px_-15px_rgba(59,130,246,0.15)]; + @apply before:content-[""] before:absolute before:top-0 before:left-0 before:w-full before:h-[2px] before:bg-blue-500 before:shadow-[0_0_10px_2px_rgba(59,130,246,0.4)]; + @apply after:content-[""] after:absolute after:top-0 after:left-0 after:right-0 after:h-16 after:bg-gradient-to-b after:from-blue-100 after:to-white after:rounded-t-md after:pointer-events-none; + /* Dark mode overrides */ + @apply dark:from-white/10 dark:to-black/30 dark:border-blue-500/30 dark:shadow-[0_10px_30px_-15px_rgba(0,0,0,0.7)]; + @apply dark:before:shadow-[0_0_20px_5px_rgba(59,130,246,0.7)]; + @apply dark:after:from-blue-500/20 dark:after:to-blue-500/5; + } + /* Hide scrollbar but allow scrolling */ + .hide-scrollbar { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + } + .hide-scrollbar::-webkit-scrollbar { + display: none; /* Chrome, Safari and Opera */ + } + /* Card flip animations */ + .flip-card .backface-hidden { + backface-visibility: hidden; + -webkit-backface-visibility: hidden; + } + .rotate-y-180 { + transform: rotateY(180deg); + } + .transform-style-preserve-3d { + transform-style: preserve-3d; + -webkit-transform-style: preserve-3d; + } +} +/* Animation delays */ +.animation-delay-150 { + animation-delay: 150ms; +} +.animation-delay-300 { + animation-delay: 300ms; +} + +/* Card expansion animation */ +.card-collapsed { + height: 140px; + transition: height 0.5s ease-in-out; +} + +.card-expanded { + height: 280px; + transition: height 0.5s ease-in-out; +} + +/* Ensure scrollable content in expanded cards */ +.card-expanded .flex-1.overflow-hidden > .absolute { + /* Removed max-height to allow full scrolling */ +} + +/* Screensaver Animations */ +@keyframes pulse { + 0% { + transform: scale(0); + opacity: 1; + } + 100% { + transform: scale(1); + opacity: 0; + } +} + +@keyframes float { + 0%, 100% { + transform: translateY(0) translateX(0); + } + 33% { + transform: translateY(-30px) translateX(10px); + } + 66% { + transform: translateY(30px) translateX(-10px); + } +} + +@keyframes breathe { + 0%, 100% { + transform: scale(1); + } + 50% { + transform: scale(1.05); + } +} + +@keyframes hologram { + 0%, 100% { + opacity: 1; + transform: rotateY(0deg) scale(1); + } + 50% { + opacity: 0.8; + transform: rotateY(10deg) scale(1.02); + } +} + +@keyframes scan { + 0% { + transform: translateY(-100%); + } + 100% { + transform: translateY(100%); + } +} + +@keyframes etherealFloat { + 0%, 100% { + transform: translateY(0) scale(1); + opacity: 0.6; + } + 50% { + transform: translateY(-20px) scale(1.05); + opacity: 0.8; + } +} + +@keyframes glow { + 0%, 100% { + transform: scale(1); + opacity: 0.6; + } + 50% { + transform: scale(1.1); + opacity: 0.8; + } +} + +@keyframes pulse-glow { + 0%, 100% { + box-shadow: 0 0 20px 10px rgba(59, 130, 246, 0.5), + 0 0 40px 20px rgba(59, 130, 246, 0.3); + } + 50% { + box-shadow: 0 0 30px 15px rgba(59, 130, 246, 0.7), + 0 0 60px 30px rgba(59, 130, 246, 0.4); + } +} + +.animate-pulse-glow { + animation: pulse-glow 2s ease-in-out infinite; +} + +/* Custom scrollbar styles */ +.custom-scrollbar { + scrollbar-width: thin; + scrollbar-color: rgba(59, 130, 246, 0.3) transparent; +} + +.custom-scrollbar::-webkit-scrollbar { + width: 8px; +} + +.custom-scrollbar::-webkit-scrollbar-track { + background: transparent; +} + +.custom-scrollbar::-webkit-scrollbar-thumb { + background-color: rgba(59, 130, 246, 0.3); + border-radius: 4px; + transition: background-color 0.2s ease; +} + +.custom-scrollbar::-webkit-scrollbar-thumb:hover { + background-color: rgba(59, 130, 246, 0.5); +} + +.dark .custom-scrollbar::-webkit-scrollbar-thumb { + background-color: rgba(59, 130, 246, 0.4); +} + +.dark .custom-scrollbar::-webkit-scrollbar-thumb:hover { + background-color: rgba(59, 130, 246, 0.6); +} + +/* Thin scrollbar styles */ +.scrollbar-thin { + scrollbar-width: thin; + scrollbar-color: rgba(156, 163, 175, 0.5) transparent; +} + +.scrollbar-thin::-webkit-scrollbar { + width: 6px; + height: 6px; +} + +.scrollbar-thin::-webkit-scrollbar-track { + background: transparent; +} + +.scrollbar-thin::-webkit-scrollbar-thumb { + background-color: rgba(156, 163, 175, 0.5); + border-radius: 3px; +} + +.scrollbar-thin::-webkit-scrollbar-thumb:hover { + background-color: rgba(156, 163, 175, 0.7); +} + +.dark .scrollbar-thin::-webkit-scrollbar-thumb { + background-color: rgba(75, 85, 99, 0.5); +} + +.dark .scrollbar-thin::-webkit-scrollbar-thumb:hover { + background-color: rgba(75, 85, 99, 0.7); +} + + +================================================ +FILE: archon-ui-main/src/index.tsx +================================================ +import './index.css'; +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import { App } from './App'; + +const container = document.getElementById('root'); +if (container) { + const root = createRoot(container); + root.render(); +} + + +================================================ +FILE: archon-ui-main/src/components/BackendStartupError.tsx +================================================ +import React from 'react'; +import { AlertCircle, Terminal, RefreshCw } from 'lucide-react'; + +export const BackendStartupError: React.FC = () => { + const handleRetry = () => { + // Reload the page to retry + window.location.reload(); + }; + + return ( +
+
+
+
+ +
+

+ Backend Service Startup Failure +

+ +

+ The Archon backend service failed to start. This is typically due to a configuration issue. +

+ +
+
+ + Check Docker Logs +
+

+ Check the Archon-Server logs in Docker Desktop for detailed error information. +

+
+

1. Open Docker Desktop

+

2. Go to Containers tab

+

3. Click on Archon-Server

+

4. View the logs for the specific error message

+
+
+ +
+

+ Common issue: Using an ANON key instead of SERVICE key in your .env file +

+
+ +
+

+ After fixing the issue in your .env file, recreate the Docker containers: +

+ + docker compose down && docker compose up -d + +

+ Note: Use 'down' and 'up', not 'restart' - containers need to be recreated to load new environment variables +

+
+ +
+ +
+
+
+
+
+
+ ); +}; + + +================================================ +FILE: archon-ui-main/src/components/DisconnectScreenOverlay.tsx +================================================ +import React, { useState } from 'react'; +import { X, Wifi, WifiOff } from 'lucide-react'; +import { DisconnectScreen } from './animations/DisconnectScreenAnimations'; +import { NeonButton } from './ui/NeonButton'; + +interface DisconnectScreenOverlayProps { + isActive: boolean; + onDismiss?: () => void; +} + +export const DisconnectScreenOverlay: React.FC = ({ + isActive, + onDismiss +}) => { + const [showControls, setShowControls] = useState(false); + + if (!isActive) return null; + + return ( +
setShowControls(true)} + onMouseEnter={() => setShowControls(true)} + onMouseLeave={() => setTimeout(() => setShowControls(false), 3000)} + > + {/* Disconnect Screen Animation */} + + + {/* Override Button */} +
+ {onDismiss && ( + + + Dismiss + + )} +
+
+ ); +}; + + +================================================ +FILE: archon-ui-main/src/components/ProjectCreationProgressCard.tsx +================================================ +import React, { useState } from 'react'; +import { Card } from './ui/Card'; +import { motion, AnimatePresence } from 'framer-motion'; +import { + CheckCircle, + XCircle, + Loader2, + FileText, + ChevronDown, + ChevronUp, + RotateCcw, + Clock, + Bot, + BrainCircuit, + BookOpen, + Database, + AlertCircle +} from 'lucide-react'; +import { Button } from './ui/Button'; +import { ProjectCreationProgressData } from '../services/projectCreationProgressService'; + +interface ProjectCreationProgressCardProps { + progressData: ProjectCreationProgressData; + onComplete?: (data: ProjectCreationProgressData) => void; + onError?: (error: string) => void; + onRetry?: () => void; + connectionStatus?: 'connected' | 'connecting' | 'disconnected' | 'error'; +} + +export const ProjectCreationProgressCard: React.FC = ({ + progressData, + onComplete, + onError, + onRetry, + connectionStatus = 'connected' +}) => { + const [showLogs, setShowLogs] = useState(false); + const [hasCompletedRef] = useState({ value: false }); + const [hasErroredRef] = useState({ value: false }); + + // Handle completion/error events + React.useEffect(() => { + if (progressData.status === 'completed' && onComplete && !hasCompletedRef.value) { + hasCompletedRef.value = true; + onComplete(progressData); + } else if (progressData.status === 'error' && onError && !hasErroredRef.value) { + hasErroredRef.value = true; + onError(progressData.error || 'Project creation failed'); + } + }, [progressData.status, onComplete, onError, progressData, hasCompletedRef, hasErroredRef]); + + const getStatusIcon = () => { + switch (progressData.status) { + case 'completed': + return ; + case 'error': + return ; + case 'initializing_agents': + return ; + case 'generating_docs': + case 'processing_requirements': + case 'ai_generation': + return ; + case 'finalizing_docs': + return ; + case 'saving_to_database': + return ; + default: + return ; + } + }; + + const getStatusColor = () => { + switch (progressData.status) { + case 'completed': + return 'text-green-500'; + case 'error': + return 'text-red-500'; + case 'initializing_agents': + return 'text-blue-500'; + case 'generating_docs': + case 'processing_requirements': + case 'ai_generation': + return 'text-purple-500'; + case 'finalizing_docs': + return 'text-indigo-500'; + case 'saving_to_database': + return 'text-green-500'; + default: + return 'text-blue-500'; + } + }; + + const getStatusText = () => { + switch (progressData.status) { + case 'starting': + return 'Starting project creation...'; + case 'initializing_agents': + return 'Initializing AI agents...'; + case 'generating_docs': + return 'Generating documentation...'; + case 'processing_requirements': + return 'Processing requirements...'; + case 'ai_generation': + return 'AI is creating project docs...'; + case 'finalizing_docs': + return 'Finalizing documents...'; + case 'saving_to_database': + return 'Saving to database...'; + case 'completed': + return 'Project created successfully!'; + case 'error': + return 'Project creation failed'; + default: + return 'Processing...'; + } + }; + + const isActive = progressData.status !== 'completed' && progressData.status !== 'error'; + + return ( + + {/* Header */} +
+
+ {getStatusIcon()} +
+

+ Creating Project: {progressData.project?.title || 'New Project'} +

+

+ {getStatusText()} +

+
+
+ + {progressData.eta && isActive && ( +
+ + {progressData.eta} +
+ )} +
+ + {/* Connection Status Indicator */} + {connectionStatus !== 'connected' && ( +
+
+ {connectionStatus === 'connecting' && } + {connectionStatus === 'disconnected' && } + {connectionStatus === 'error' && } + + {connectionStatus === 'connecting' && 'Connecting to progress stream...'} + {connectionStatus === 'disconnected' && 'Disconnected from progress stream'} + {connectionStatus === 'error' && 'Connection error - retrying...'} + +
+
+ )} + + {/* Progress Bar */} +
+
+ + Progress + + + {progressData.percentage}% + +
+
+ +
+
+ + {/* Step Information */} + {progressData.step && ( +
+
+ Current Step: + + {progressData.step} + +
+
+ )} + + {/* Error Information */} + {progressData.status === 'error' && ( +
+
+ Error: {progressData.error || 'Project creation failed'} + {progressData.progressId && ( +
+ Progress ID: {progressData.progressId} +
+ )} +
+
+ )} + + {/* Debug Information - Show when stuck on starting status */} + {progressData.status === 'starting' && progressData.percentage === 0 && connectionStatus === 'connected' && ( +
+
+ Debug: Connected to progress stream but no updates received yet. +
+ Progress ID: {progressData.progressId} +
+
+ Check browser console for Socket.IO connection details. +
+
+
+ )} + + {/* Duration (when completed) */} + {progressData.status === 'completed' && progressData.duration && ( +
+
+ Completed in: {progressData.duration} +
+
+ )} + + {/* Console Logs */} + {progressData.logs && progressData.logs.length > 0 && ( +
+ + + + {showLogs && ( + +
+
+ {progressData.logs.map((log, index) => ( +
+ {log} +
+ ))} +
+
+
+ )} +
+
+ )} + + {/* Action Buttons */} + {progressData.status === 'error' && onRetry && ( +
+ +
+ )} +
+ ); +}; + + +================================================ +FILE: archon-ui-main/src/components/animations/Animations.tsx +================================================ +import React from 'react'; +/** + * ArchonLoadingSpinner - A loading animation component with neon trail effects + * + * This component displays the Archon logo with animated spinning circles + * that create a neon trail effect. It's used to indicate loading states + * throughout the application. + * + * @param {Object} props - Component props + * @param {string} props.size - Size variant ('sm', 'md', 'lg') + * @param {string} props.logoSrc - Source URL for the logo image + * @param {string} props.className - Additional CSS classes + */ +export const ArchonLoadingSpinner: React.FC<{ + size?: 'sm' | 'md' | 'lg'; + logoSrc?: string; + className?: string; +}> = ({ + size = 'md', + logoSrc = "/logo-neon.png", + className = '' +}) => { + // Size mappings for the container and logo + const sizeMap = { + sm: { + container: 'w-8 h-8', + logo: 'w-5 h-5' + }, + md: { + container: 'w-10 h-10', + logo: 'w-7 h-7' + }, + lg: { + container: 'w-14 h-14', + logo: 'w-9 h-9' + } + }; + return
+ {/* Central logo */} + Loading + {/* Animated spinning circles with neon trail effects */} +
+ {/* First circle - cyan with clockwise rotation */} +
+ {/* Second circle - fuchsia with counter-clockwise rotation */} +
+
+
; +}; +/** + * NeonGlowEffect - A component that adds a neon glow effect to its children + * + * This component creates a container with a neon glow effect in different colors. + * It's used for highlighting UI elements with a cyberpunk/neon aesthetic. + * + * @param {Object} props - Component props + * @param {React.ReactNode} props.children - Child elements + * @param {string} props.color - Color variant ('cyan', 'fuchsia', 'blue', 'purple', 'green', 'pink') + * @param {string} props.intensity - Glow intensity ('low', 'medium', 'high') + * @param {string} props.className - Additional CSS classes + */ +export const NeonGlowEffect: React.FC<{ + children: React.ReactNode; + color?: 'cyan' | 'fuchsia' | 'blue' | 'purple' | 'green' | 'pink'; + intensity?: 'low' | 'medium' | 'high'; + className?: string; +}> = ({ + children, + color = 'blue', + intensity = 'medium', + className = '' +}) => { + // Color mappings for different neon colors + const colorMap = { + cyan: 'border-cyan-400 shadow-cyan-400/50 dark:shadow-cyan-400/70', + fuchsia: 'border-fuchsia-400 shadow-fuchsia-400/50 dark:shadow-fuchsia-400/70', + blue: 'border-blue-400 shadow-blue-400/50 dark:shadow-blue-400/70', + purple: 'border-purple-500 shadow-purple-500/50 dark:shadow-purple-500/70', + green: 'border-emerald-500 shadow-emerald-500/50 dark:shadow-emerald-500/70', + pink: 'border-pink-500 shadow-pink-500/50 dark:shadow-pink-500/70' + }; + // Intensity mappings for glow strength + const intensityMap = { + low: 'shadow-[0_0_5px_0]', + medium: 'shadow-[0_0_10px_1px]', + high: 'shadow-[0_0_15px_2px]' + }; + return
+
+
{children}
+
; +}; +/** + * EdgeLitEffect - A component that adds an edge-lit glow effect + * + * This component creates a thin glowing line at the top of a container, + * simulating the effect of edge lighting. + * + * @param {Object} props - Component props + * @param {string} props.color - Color variant ('blue', 'purple', 'green', 'pink') + * @param {string} props.className - Additional CSS classes + */ +export const EdgeLitEffect: React.FC<{ + color?: 'blue' | 'purple' | 'green' | 'pink'; + className?: string; +}> = ({ + color = 'blue', + className = '' +}) => { + // Color mappings for different edge-lit colors + const colorMap = { + blue: 'bg-blue-500 shadow-[0_0_10px_2px_rgba(59,130,246,0.4)] dark:shadow-[0_0_20px_5px_rgba(59,130,246,0.7)]', + purple: 'bg-purple-500 shadow-[0_0_10px_2px_rgba(168,85,247,0.4)] dark:shadow-[0_0_20px_5px_rgba(168,85,247,0.7)]', + green: 'bg-emerald-500 shadow-[0_0_10px_2px_rgba(16,185,129,0.4)] dark:shadow-[0_0_20px_5px_rgba(16,185,129,0.7)]', + pink: 'bg-pink-500 shadow-[0_0_10px_2px_rgba(236,72,153,0.4)] dark:shadow-[0_0_20px_5px_rgba(236,72,153,0.7)]' + }; + return
; +}; + + +================================================ +FILE: archon-ui-main/src/components/animations/DisconnectScreenAnimations.tsx +================================================ +import React, { useEffect, useRef } from 'react'; + +/** + * Disconnect Screen + * Frosted glass medallion with aurora borealis light show behind it + */ +export const DisconnectScreen: React.FC = () => { + const canvasRef = useRef(null); + + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + + const ctx = canvas.getContext('2d'); + if (!ctx) return; + + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + + let time = 0; + + const drawAurora = () => { + // Create dark background with vignette + const gradient = ctx.createRadialGradient( + canvas.width / 2, canvas.height / 2, 0, + canvas.width / 2, canvas.height / 2, canvas.width / 1.5 + ); + gradient.addColorStop(0, 'rgba(0, 0, 0, 0.3)'); + gradient.addColorStop(1, 'rgba(0, 0, 0, 0.95)'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + // Draw aurora waves with varying opacity + const colors = [ + { r: 34, g: 211, b: 238, a: 0.4 }, // Cyan + { r: 168, g: 85, b: 247, a: 0.4 }, // Purple + { r: 236, g: 72, b: 153, a: 0.4 }, // Pink + { r: 59, g: 130, b: 246, a: 0.4 }, // Blue + { r: 16, g: 185, b: 129, a: 0.4 }, // Green + ]; + + colors.forEach((color, index) => { + ctx.beginPath(); + + const waveHeight = 250; + const waveOffset = index * 60; + const speed = 0.001 + index * 0.0002; + + // Animate opacity for ethereal effect + const opacityWave = Math.sin(time * 0.0005 + index) * 0.2 + 0.3; + + for (let x = 0; x <= canvas.width; x += 5) { + const y = canvas.height / 2 + + Math.sin(x * 0.003 + time * speed) * waveHeight + + Math.sin(x * 0.005 + time * speed * 1.5) * (waveHeight / 2) + + Math.sin(x * 0.002 + time * speed * 0.5) * (waveHeight / 3) + + waveOffset - 100; + + if (x === 0) { + ctx.moveTo(x, y); + } else { + ctx.lineTo(x, y); + } + } + + // Create gradient for each wave with animated opacity + const waveGradient = ctx.createLinearGradient(0, canvas.height / 2 - 300, 0, canvas.height / 2 + 300); + waveGradient.addColorStop(0, `rgba(${color.r}, ${color.g}, ${color.b}, 0)`); + waveGradient.addColorStop(0.5, `rgba(${color.r}, ${color.g}, ${color.b}, ${opacityWave})`); + waveGradient.addColorStop(1, `rgba(${color.r}, ${color.g}, ${color.b}, 0)`); + + ctx.strokeStyle = waveGradient; + ctx.lineWidth = 4; + ctx.stroke(); + + // Add enhanced glow effect + ctx.shadowBlur = 40; + ctx.shadowColor = `rgba(${color.r}, ${color.g}, ${color.b}, 0.6)`; + ctx.stroke(); + ctx.shadowBlur = 0; + }); + + time += 16; + requestAnimationFrame(drawAurora); + }; + + drawAurora(); + + const handleResize = () => { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + }; + + window.addEventListener('resize', handleResize); + + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + + return ( +
+ + + {/* Glass medallion with frosted effect - made bigger */} +
+
+ {/* Glowing orb effect */} +
+ + {/* Frosted glass background */} +
+ + {/* Embossed logo - made bigger */} +
+ Archon +
+ + {/* Disconnected Text - Glass style with red glow */} +
+
+ + DISCONNECTED + +
+
+
+
+
+ ); +}; + + +================================================ +FILE: archon-ui-main/src/components/bug-report/BugReportButton.tsx +================================================ +import { Bug, Loader } from "lucide-react"; +import { Button } from "../ui/Button"; +import { BugReportModal } from "./BugReportModal"; +import { useBugReport } from "../../hooks/useBugReport"; + +interface BugReportButtonProps { + error?: Error; + variant?: "primary" | "secondary" | "ghost"; + size?: "sm" | "md" | "lg"; + className?: string; + children?: React.ReactNode; +} + +export const BugReportButton: React.FC = ({ + error, + variant = "ghost", + size = "md", + className = "", + children, +}) => { + const { isOpen, context, loading, openBugReport, closeBugReport } = + useBugReport(); + + const handleClick = () => { + openBugReport(error); + }; + + return ( + <> + + + {context && ( + + )} + + ); +}; + + + +================================================ +FILE: archon-ui-main/src/components/bug-report/BugReportModal.tsx +================================================ +import { useState } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { Bug, X, Send, Copy, ExternalLink, Loader } from "lucide-react"; +import { Button } from "../ui/Button"; +import { Input } from "../ui/Input"; +import { Card } from "../ui/Card"; +import { Select } from "../ui/Select"; +import { useToast } from "../../contexts/ToastContext"; +import { + bugReportService, + BugContext, + BugReportData, +} from "../../services/bugReportService"; + +interface BugReportModalProps { + isOpen: boolean; + onClose: () => void; + context: BugContext; +} + +export const BugReportModal: React.FC = ({ + isOpen, + onClose, + context, +}) => { + const [report, setReport] = useState>({ + title: `🐛 ${context.error.name}: ${context.error.message}`, + description: "", + stepsToReproduce: "", + expectedBehavior: "", + actualBehavior: context.error.message, + severity: "medium", + component: "not-sure", + }); + + const [submitting, setSubmitting] = useState(false); + const [submitted, setSubmitted] = useState(false); + const { showToast } = useToast(); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + if (!report.description.trim()) { + showToast( + "Please provide a description of what you were trying to do", + "error", + ); + return; + } + + setSubmitting(true); + + try { + const bugReportData: BugReportData = { + ...report, + context, + }; + + const result = await bugReportService.submitBugReport(bugReportData); + + if (result.success) { + setSubmitted(true); + + if (result.issueNumber) { + // Direct API creation (maintainer with token) + showToast( + `Bug report created! Issue #${result.issueNumber} - maintainers will review it soon.`, + "success", + 8000, + ); + if (result.issueUrl) { + window.open(result.issueUrl, "_blank"); + } + } else { + // Manual submission (open source user - no token) + showToast( + "Opening GitHub to submit your bug report...", + "success", + 5000, + ); + if (result.issueUrl) { + // Force new tab/window opening + const newWindow = window.open( + result.issueUrl, + "_blank", + "noopener,noreferrer", + ); + if (!newWindow) { + // Popup blocked - show manual link + showToast( + "Popup blocked! Please allow popups or click the link in the modal.", + "warning", + 8000, + ); + } + } + } + } else { + // Fallback: copy to clipboard + const formattedReport = + bugReportService.formatReportForClipboard(bugReportData); + await navigator.clipboard.writeText(formattedReport); + + showToast( + "Failed to create GitHub issue, but bug report was copied to clipboard. Please paste it in a new GitHub issue.", + "warning", + 10000, + ); + } + } catch (error) { + console.error("Bug report submission failed:", error); + showToast( + "Failed to submit bug report. Please try again or report manually.", + "error", + ); + } finally { + setSubmitting(false); + } + }; + + const copyToClipboard = async () => { + const bugReportData: BugReportData = { ...report, context }; + const formattedReport = + bugReportService.formatReportForClipboard(bugReportData); + + try { + await navigator.clipboard.writeText(formattedReport); + showToast("Bug report copied to clipboard", "success"); + } catch { + showToast("Failed to copy to clipboard", "error"); + } + }; + + if (!isOpen) return null; + + return ( + + + e.stopPropagation()} + > + + {/* Header */} +
+
+ +

+ Report Bug +

+
+ +
+ + {submitted ? ( + /* Success State */ +
+
+ +
+

+ Bug Report Submitted! +

+

+ Thank you for helping improve Archon. Maintainers will review + your report and may comment @claude to trigger automatic + analysis and fixes. +

+ +
+ ) : ( + /* Form */ +
+ {/* Error Preview */} +
+
+ {context.error.name}: {context.error.message} +
+ {context.error.stack && ( +
+ + Stack trace + +
+                        {context.error.stack}
+                      
+
+ )} +
+ + {/* Bug Title */} + + setReport((r) => ({ ...r, title: e.target.value })) + } + placeholder="Brief description of the bug" + required + /> + + {/* Severity & Component */} +
+ + setReport((r) => ({ ...r, component: e.target.value })) + } + options={[ + { + value: "knowledge-base", + label: "🔍 Knowledge Base / RAG", + }, + { value: "mcp-integration", label: "🔗 MCP Integration" }, + { value: "projects-tasks", label: "📋 Projects & Tasks" }, + { + value: "settings", + label: "⚙️ Settings & Configuration", + }, + { value: "ui", label: "🖥️ User Interface" }, + { + value: "infrastructure", + label: "🐳 Docker / Infrastructure", + }, + { value: "not-sure", label: "❓ Not Sure" }, + ]} + /> +
+ + {/* Description */} +
+ +