|
|
"""Context7-powered documentation agent for deployment readiness.""" |
|
|
|
|
|
from __future__ import annotations |
|
|
|
|
|
import os |
|
|
from typing import Any, Dict, List, Optional |
|
|
|
|
|
from enhanced_mcp_client import EnhancedMCPClient |
|
|
from schemas import ReadinessPlan, ReadinessRequest |
|
|
|
|
|
|
|
|
class DocumentationLookupAgent: |
|
|
"""Uses Context7 MCP to lookup framework/platform documentation.""" |
|
|
|
|
|
def __init__(self): |
|
|
self.mcp_client = EnhancedMCPClient() |
|
|
|
|
|
async def extract_framework_from_request(self, request: ReadinessRequest) -> Optional[str]: |
|
|
"""Extract framework/library from code summary with multi-framework support.""" |
|
|
code_lower = request.code_summary.lower() |
|
|
infra_lower = (request.infra_notes or "").lower() |
|
|
combined = f"{code_lower} {infra_lower}" |
|
|
|
|
|
|
|
|
frameworks = { |
|
|
|
|
|
"next.js": "next.js", |
|
|
"nextjs": "next.js", |
|
|
"remix": "remix", |
|
|
"gatsby": "gatsby", |
|
|
|
|
|
"django": "django", |
|
|
"fastapi": "fastapi", |
|
|
"flask": "flask", |
|
|
"fastapi": "fastapi", |
|
|
"starlette": "starlette", |
|
|
|
|
|
"express": "express", |
|
|
"nestjs": "nestjs", |
|
|
"koa": "koa", |
|
|
"hapi": "hapi", |
|
|
|
|
|
"react": "react", |
|
|
"vue": "vue", |
|
|
"angular": "angular", |
|
|
"svelte": "svelte", |
|
|
"nuxt": "nuxt", |
|
|
|
|
|
"spring": "spring", |
|
|
"rails": "rails", |
|
|
"laravel": "laravel", |
|
|
} |
|
|
|
|
|
|
|
|
detected = [] |
|
|
for key, framework in frameworks.items(): |
|
|
if key in combined: |
|
|
detected.append((len(key), framework)) |
|
|
|
|
|
if detected: |
|
|
|
|
|
detected.sort(reverse=True, key=lambda x: x[0]) |
|
|
return detected[0][1] |
|
|
|
|
|
return None |
|
|
|
|
|
async def extract_platform_from_request(self, request: ReadinessRequest) -> Optional[str]: |
|
|
"""Extract deployment platform from infra notes with multi-platform support.""" |
|
|
infra_lower = (request.infra_notes or "").lower() |
|
|
code_lower = (request.code_summary or "").lower() |
|
|
combined = f"{infra_lower} {code_lower}" |
|
|
|
|
|
|
|
|
platforms = { |
|
|
|
|
|
"vercel": "vercel", |
|
|
"netlify": "netlify", |
|
|
"cloudflare": "cloudflare", |
|
|
"cloudflare pages": "cloudflare", |
|
|
|
|
|
"aws": "aws", |
|
|
"amazon web services": "aws", |
|
|
"azure": "azure", |
|
|
"microsoft azure": "azure", |
|
|
"gcp": "gcp", |
|
|
"google cloud": "gcp", |
|
|
"google cloud platform": "gcp", |
|
|
|
|
|
"railway": "railway", |
|
|
"render": "render", |
|
|
"fly.io": "fly.io", |
|
|
"flyio": "fly.io", |
|
|
"heroku": "heroku", |
|
|
"digitalocean": "digitalocean", |
|
|
"digital ocean": "digitalocean", |
|
|
|
|
|
"kubernetes": "kubernetes", |
|
|
"k8s": "kubernetes", |
|
|
"docker": "docker", |
|
|
"docker compose": "docker", |
|
|
"docker-compose": "docker", |
|
|
} |
|
|
|
|
|
|
|
|
detected = [] |
|
|
for key, platform in platforms.items(): |
|
|
if key in combined: |
|
|
detected.append((len(key), platform)) |
|
|
|
|
|
if detected: |
|
|
detected.sort(reverse=True, key=lambda x: x[0]) |
|
|
return detected[0][1] |
|
|
|
|
|
return None |
|
|
|
|
|
async def lookup_deployment_docs( |
|
|
self, request: ReadinessRequest, plan: ReadinessPlan |
|
|
) -> Dict[str, Any]: |
|
|
"""Comprehensive documentation lookup for deployment readiness.""" |
|
|
framework = await self.extract_framework_from_request(request) |
|
|
platform = await self.extract_platform_from_request(request) |
|
|
|
|
|
docs_results = { |
|
|
"framework": framework, |
|
|
"platform": platform, |
|
|
"lookups": [] |
|
|
} |
|
|
|
|
|
if not framework and not platform: |
|
|
docs_results["lookups"].append({ |
|
|
"type": "general", |
|
|
"topic": "deployment best practices", |
|
|
"status": "no_framework_detected" |
|
|
}) |
|
|
return docs_results |
|
|
|
|
|
|
|
|
if framework: |
|
|
framework_docs = await self.mcp_client.lookup_documentation( |
|
|
framework, "deployment guide" |
|
|
) |
|
|
docs_results["lookups"].append({ |
|
|
"type": "framework_deployment", |
|
|
"framework": framework, |
|
|
"docs": framework_docs, |
|
|
"status": "found" if framework_docs.get("success") else "not_found" |
|
|
}) |
|
|
|
|
|
|
|
|
if platform: |
|
|
platform_docs = await self.mcp_client.lookup_documentation( |
|
|
platform, "deployment configuration" |
|
|
) |
|
|
docs_results["lookups"].append({ |
|
|
"type": "platform_deployment", |
|
|
"platform": platform, |
|
|
"docs": platform_docs, |
|
|
"status": "found" if platform_docs.get("success") else "not_found" |
|
|
}) |
|
|
|
|
|
|
|
|
if framework: |
|
|
|
|
|
deps = [] |
|
|
compat_check = await self.mcp_client.check_dependency_compatibility( |
|
|
deps, framework |
|
|
) |
|
|
docs_results["lookups"].append({ |
|
|
"type": "dependency_compatibility", |
|
|
"result": compat_check, |
|
|
"status": "checked" |
|
|
}) |
|
|
|
|
|
|
|
|
if platform: |
|
|
config_validation = await self.mcp_client.validate_deployment_config( |
|
|
"dockerfile", "", platform |
|
|
) |
|
|
docs_results["lookups"].append({ |
|
|
"type": "config_validation", |
|
|
"result": config_validation, |
|
|
"status": "validated" |
|
|
}) |
|
|
|
|
|
|
|
|
if framework and platform: |
|
|
runbook = await self.mcp_client.get_deployment_runbook( |
|
|
framework, platform, "production" |
|
|
) |
|
|
docs_results["lookups"].append({ |
|
|
"type": "deployment_runbook", |
|
|
"result": runbook, |
|
|
"status": "generated" |
|
|
}) |
|
|
|
|
|
|
|
|
if framework: |
|
|
env_check = await self.mcp_client.check_environment_variables( |
|
|
[], framework |
|
|
) |
|
|
docs_results["lookups"].append({ |
|
|
"type": "environment_variables", |
|
|
"result": env_check, |
|
|
"status": "checked" |
|
|
}) |
|
|
|
|
|
|
|
|
if framework: |
|
|
migration_guide = await self.mcp_client.get_migration_guide( |
|
|
framework, "database" |
|
|
) |
|
|
docs_results["lookups"].append({ |
|
|
"type": "migration_guide", |
|
|
"result": migration_guide, |
|
|
"status": "found" |
|
|
}) |
|
|
|
|
|
|
|
|
if framework and platform: |
|
|
observability = await self.mcp_client.get_observability_setup( |
|
|
framework, platform |
|
|
) |
|
|
docs_results["lookups"].append({ |
|
|
"type": "observability_setup", |
|
|
"result": observability, |
|
|
"status": "found" |
|
|
}) |
|
|
|
|
|
return docs_results |
|
|
|
|
|
def generate_readme(self, analysis: Dict[str, Any]) -> str: |
|
|
"""Generate a professional README.md based on analysis.""" |
|
|
framework = analysis.get("framework", "Project") |
|
|
summary = analysis.get("code_summary", "No summary available.") |
|
|
dependencies = analysis.get("dependencies", []) |
|
|
platform = analysis.get("platform", "Not configured") |
|
|
|
|
|
|
|
|
badges = f"})\n" |
|
|
if platform != "Not configured": |
|
|
badges += f"})\n" |
|
|
|
|
|
readme = f"""# {framework.title()} Project |
|
|
|
|
|
{badges} |
|
|
|
|
|
## π Overview |
|
|
{summary} |
|
|
|
|
|
## π οΈ Tech Stack |
|
|
| Component | Details | |
|
|
|-----------|---------| |
|
|
| **Framework** | {framework} | |
|
|
| **Platform** | {platform} | |
|
|
| **Dependencies** | {len(dependencies)} packages | |
|
|
|
|
|
## π¦ Installation |
|
|
|
|
|
```bash |
|
|
""" |
|
|
if analysis.get("package_manager") == "npm": |
|
|
readme += "npm install\nnpm run dev\n" |
|
|
elif analysis.get("package_manager") == "pip": |
|
|
readme += "pip install -r requirements.txt\npython app.py\n" |
|
|
else: |
|
|
readme += "# Install dependencies\n# Run application\n" |
|
|
|
|
|
readme += """``` |
|
|
|
|
|
## π’ Deployment |
|
|
|
|
|
This project is ready for deployment via **Deploy Ready Copilot**. |
|
|
|
|
|
### Steps |
|
|
1. Connect your GitHub repository. |
|
|
2. Select your target platform ({platform}). |
|
|
3. Click "Deploy". |
|
|
|
|
|
--- |
|
|
*Generated by [Deploy Ready Copilot](https://huggingface.co/spaces/HIMANSHUKUMARJHA/deploy-ready-copilot)* |
|
|
""" |
|
|
return readme |
|
|
|