Feat/search console verification#37
Merged
Merged
Conversation
- Implement circular dependency detection on adjacency list - Add percentile-based file complexity heatmap to graph nodes - Introduce orphan file detection for dead code identification - Update node state interfaces and UI legends
…nents - Extract state management, LLM streaming, and graph traversal into custom hooks - Modularize UI into dedicated layout components (Visualizer, Doctor, Risk Radar) - Isolate static configurations and types into constants.ts - Strip page.tsx down to act strictly as a layout orchestrator
- Extract changed files from existing PR analysis route - Add 'pr-blast' highlight mode to React Flow ArchitectureMap - Implement automatic tab switching and state lifting for seamless UX
…ive dashboard - **Algorithms**: Shipped zero-latency, pure math static analysis features including Articulation Points (Bridge Detection), Dead Code Reachability (BFS), Dependency PageRank, and Robert C. Martin's Instability Matrix (Ca/Ce coupling). - **Architecture Insights UI**: Built the new `ArchInsightsPanel` and `InfoTooltip` to visualize critical single-points-of-failure, unreachable code chunks, and codebase stability metrics directly over the React Flow canvas. - **Pipeline Integration**: Upgraded `ast-pipeline.ts` and `analyze.ts` types to support the new graph theory outputs without triggering external API calls. - **Command Center Dashboard**: Extracted flat dashboard list into a client-side `DashboardGrid` component. Added interactive grouping by repository, analysis count badges, and chronological sorting with formatted timestamps.
…hangedFiles comment
- Add checkout API route (/api/checkout) - Add webhook handler (/api/webhooks/lemonsqueezy) - Update usage.ts to support pro tier (100/day limit) - Update analyze route to use ratelimitPro for pro users - Update chat route to bypass limit for pro users - Update analyze-pr route to bypass limit for pro users - Add ratelimitPro to ratelimit.ts - Supabase profiles table created with plan_tier column
- Add handleUpgrade function calling /api/checkout - Update tier names: Student→Intern, Architect→Specialist, Surgical→Chief Surgeon - Specialist tier now live with ₹99/mo and amber styling - Add loading state and login redirect for unauthenticated users - Remove Coming Soon badge from Specialist tier
- Free tier: context 20k -> 6k chars, max_tokens 1024 -> 512 - Pro tier: context 14k chars, max_tokens 1024, deepseek-r1 model - Reduces token usage by ~70% for free tier chat
Amber color tokens felt out of place against the dark technical aesthetic. Replaced all amber instances in RiskDashboard with the existing slate/white/transparent vocabulary used throughout the component. - Pro banner: amber border/bg → white/5 glass surface - Upgrade button: amber fills → slate-300/white hover - Locked Auto-Patch button: amber tint → desaturated slate-500 - FileCode icon: amber-400 → slate-300 with white hover - Traffic light middle dot: amber-500 → slate-500
Amber color tokens felt out of place against the dark technical aesthetic. Replaced all amber instances in RiskDashboard with the existing slate/white/transparent vocabulary used throughout the component. - Pro banner: amber border/bg → white/5 glass surface - Upgrade button: amber fills → slate-300/white hover - Locked Auto-Patch button: amber tint → desaturated slate-500 - FileCode icon: amber-400 → slate-300 with white hover - Traffic light middle dot: amber-500 → slate-500
- fix: dynamic analysis_version query instead of hardcoded v3 - fix: separate visited sets for upstream/downstream BFS traversal - fix: node ID collision in mermaid sanitizer (path-aware) - fix: opacity replaced with stroke-width in mermaid styles - fix: JSON.parse wrapped in try/catch in cache and groq-debug - fix: requiresRuntimeCheck narrowed to specific runtime patterns - fix: at async removed from framework noise filter in stack-parser - fix: findMatchingFile disambiguates same-name files by path score - perf: parallel file fetching via Promise.allSettled - perf: reverse graph memoized via WeakMap - perf: BFS queue uses head pointer instead of array.shift() - refactor: rename gemini-debug to groq-debug with backward alias - refactor: confidence removed from AI prompt, heuristics only - remove: dead code generateErrorGraph and extractAllCrashNodes - add: cache invalidation via invalidateRepoCache() - add: server-side rate limiting with 429 response
The React Flow node/edge renderer — wherever node styles and badges are applied The right analysis panel — wherever CIRCULAR DEPS / ORPHANS / NERVE CENTER are rendered The Risk Radar tab — its current state
…d as prop - Add computePageRank() helper using damped iteration (20 passes, 0.85 factor) - Normalize scores to 0-100 range for consistent tier thresholds - Add computedPageRankScores useMemo that falls back to internal computation - Replace all pageRankScores references with computedPageRankScores - Nerve Center panel now works out of the box without parent wiring
- Logged-in users now get a fresh DB row on every analysis (cached or not) so the dashboard always reflects the latest activity with correct timestamp - RAG storage still skipped for cached results to avoid redundant processing - Anon users retain original behavior (insert only on fresh analyses) Fixes: dashboard showing stale May 29 dates after re-analyzing existing repos
- Switch all routes from llama-3.3-70b-versatile to llama-3.1-8b-instant (5x higher token limit: 100K -> 500K TPD, same free tier) - Cache AI response in analyses.ai_response column after first run so repeat analysis of same repo costs 0 tokens - Tee live stream to store response without breaking streaming UX - Cap fileContents to top 20 files in gemini.ts to prevent token blowout on large repos (was sending all files unbounded)
…ty, and cfg builder
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR introduces SEO/search-console verification assets (Google verification meta, sitemap/robots generation) while significantly expanding the analysis pipeline with new graph metrics (betweenness centrality), CFG-based findings, stronger file filtering, and multiple performance/caching improvements across the API and UI.
Changes:
- Add sitemap/robots + Google Search Console verification metadata, and wire
next-sitemapintopostbuild. - Expand repo analysis output with betweenness centrality + CFG findings/summary, plus graph quality metadata and improved file selection.
- Add caching behaviors for analyses/AI responses and optimize ReactFlow visualizers to reduce expensive re-renders.
Reviewed changes
Copilot reviewed 28 out of 31 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| public/sitemap.xml | Adds sitemap index for search engines. |
| public/sitemap-0.xml | Adds first sitemap URL set for site pages. |
| public/robots.txt | Adds crawler directives and sitemap reference. |
| package.json | Adds next-sitemap postbuild + new deps/devDeps (incl. Puppeteer). |
| package-lock.json | Locks dependency updates for new/updated packages. |
| next-sitemap.config.js | Adds next-sitemap configuration for sitemap/robots generation. |
| lib/types/analyze.ts | Extends analysis types with betweenness + CFG fields. |
| lib/pipeline/ast-pipeline.ts | Adds filtering, graph quality, betweenness + CFG analysis, and depth-based file selection. |
| lib/gemini.ts | Switches OpenAI-compatible endpoint/key and caps file context sent to the model. |
| lib/file-filter.ts | Introduces repo-type detection + stricter file/graph-node gating + graph quality assessment. |
| lib/dependency-graph.ts | Adds depth-based traversal (getFilesByDepth) for selecting important files. |
| lib/debug/groq-debug.ts | Updates model selection for debug analysis calls. |
| lib/cfg-builder.ts | Adds Babel-based CFG-oriented static findings extraction for JS/TS. |
| lib/analysis-cache.ts | Adds a Supabase-backed cache utility layer (staleness + invalidation). |
| lib/algorithms/betweenness.ts | Adds Brandes betweenness centrality + severity mapping utilities. |
| lib/algorithms/tests/betweenness.test.ts | Adds unit tests for betweenness algorithm + severity mapping. |
| lib/tests/file-filter.test.ts | Adds tests for new file-filter skip rules. |
| lib/tests/dependency-graph-depth.test.ts | Adds tests for new depth-based file selection. |
| lib/tests/cfg-builder.test.ts | Adds tests for CFG findings and summarization. |
| generate-og.js | Adds OG image generator script using Puppeteer. |
| components/DirectoryTreeVisualizer.tsx | Avoids recreating ReactFlow nodeTypes on each render. |
| components/ArchitectureMap.tsx | Adds betweenness overlays + memoization/perf refactors for ReactFlow graph rendering. |
| components/analyze/VisualizerPanel.tsx | Plumbs betweenness scores into graph view and adds a legend hint. |
| app/layout.tsx | Adds Google verification + JSON-LD structured data in the root layout. |
| app/api/v1/analyze/route.ts | Bumps analysis version to match updated pipeline output. |
| app/api/generate-test/route.ts | Updates model selection for test generation. |
| app/api/analyze/route.ts | Bumps analysis version and adjusts caching/insert behavior (incl. user scoping). |
| app/api/analyze-pr/route.ts | Updates model selection for PR analysis. |
| app/api/ai/route.ts | Adds AI-response cache read + background writeback to analyses. |
| app/analyze/page.tsx | Passes betweenness scores into the visualizer panel. |
Files not reviewed (1)
- generate-og.js: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+1
to
+25
| /** @type {import('next-sitemap').IConfig} */ | ||
| const config = { | ||
| siteUrl: 'https://codeautopsy-lyart.vercel.app', | ||
| generateRobotsTxt: true, | ||
| exclude: [ | ||
| '/api/*', | ||
| '/auth/*', | ||
| '/dashboard', | ||
| '/dashboard/*', | ||
| '/profile', | ||
| '/history', | ||
| '/analyze', | ||
| '/pr-scan', | ||
| '/view/*', | ||
| '/actions/*', | ||
| ], | ||
| robotsTxtOptions: { | ||
| policies: [ | ||
| { userAgent: '*', allow: '/' }, | ||
| { userAgent: '*', disallow: ['/api/', '/auth/', '/dashboard/', '/profile/', '/history/', '/analyze/', '/pr-scan/', '/view/'] }, | ||
| ], | ||
| }, | ||
| }; | ||
|
|
||
| export default config; |
Comment on lines
+139
to
+149
| try { | ||
| const { error } = await supabase | ||
| .from("analyses") | ||
| .update({ ai_response: fullResponse }) | ||
| .eq("repo_url", repoUrl) | ||
| .eq("user_id", user.id) | ||
| .order("created_at", { ascending: false }) | ||
| .limit(1); | ||
|
|
||
| if (error) console.error("[ai] Cache store failed:", error.message); | ||
| else console.log("[ai] AI response cached for future calls"); |
Comment on lines
219
to
+223
| .select("result_json") | ||
| .eq("repo_url", repoUrl) | ||
| .eq("commit_sha", commitSha) | ||
| .eq("analysis_version", ANALYSIS_VERSION) | ||
| .eq("user_id", userId ?? "") |
Comment on lines
+31
to
+55
| export async function getLatestCommitSha( | ||
| owner: string, | ||
| repo: string, | ||
| githubToken: string, | ||
| ): Promise<string | null> { | ||
| try { | ||
| const res = await fetch( | ||
| `https://api.github.com/repos/${owner}/${repo}/commits/HEAD`, | ||
| { | ||
| headers: { | ||
| Authorization: `Bearer ${githubToken}`, | ||
| Accept: "application/vnd.github+json", | ||
| "X-GitHub-Api-Version": "2022-11-28", | ||
| }, | ||
| next: { revalidate: 60 }, // Next.js fetch cache: 1 min | ||
| }, | ||
| ); | ||
|
|
||
| if (!res.ok) return null; | ||
| const data = await res.json(); | ||
| return typeof data?.sha === "string" ? data.sha : null; | ||
| } catch { | ||
| return null; | ||
| } | ||
| } |
Comment on lines
+86
to
+95
| const { data: row } = await supabase | ||
| .from("analyses") | ||
| .select("commit_sha, created_at") | ||
| .eq("repo_url", repoUrl) | ||
| .eq("analysis_version", ANALYSIS_VERSION) | ||
| .eq("user_id", userId ?? "") | ||
| .gte("created_at", staleCutoff) | ||
| .order("created_at", { ascending: false }) | ||
| .limit(1) | ||
| .maybeSingle(); |
Comment on lines
+5
to
+24
| // Cache key: analyses table row keyed on (repo_url, commit_sha, analysis_version, user_id). | ||
| // This table already exists in your Supabase schema (confirmed from screenshot). | ||
| // The pipeline already reads from it via the checkCache callback in runAstPipeline. | ||
| // This module adds the three missing pieces: | ||
| // 1. getLatestCommitSha — fetches the HEAD sha from GitHub API. | ||
| // 2. isCacheStale — compares stored commit_sha vs live HEAD. | ||
| // 3. invalidateUserCache — hard-deletes rows for a (repo_url, user_id) pair. | ||
| // 4. forceReanalyze — used by /api/reanalyze route to bust cache. | ||
| // | ||
| // TTL is enforced via a Postgres partial index or a where-clause filter on | ||
| // created_at. No cron needed — stale rows are just ignored on read, and | ||
| // the nightly Supabase pg_cron cleanup (if configured) handles GC. | ||
|
|
||
| import { SupabaseClient } from "@supabase/supabase-js"; | ||
|
|
||
| const CACHE_TTL_HOURS = 24; | ||
| const ANALYSIS_VERSION = 14; // keep in sync with app/api/analyze/route.ts | ||
|
|
||
| // ── GitHub HEAD sha ────────────────────────────────────────────────────────A | ||
|
|
Comment on lines
+612
to
+613
| const fanInValues = Object.values(fanIn); | ||
| const maxFanIn = fanInValues.length > 0 ? Math.max(...fanInValues) : 0; |
| "husky": "^9.1.7", | ||
| "lint-staged": "^17.0.5", | ||
| "prettier": "^3.8.3", | ||
| "puppeteer": "^25.1.0", |
Comment on lines
+1
to
+20
| # * | ||
| User-agent: * | ||
| Allow: / | ||
|
|
||
| # * | ||
| User-agent: * | ||
| Disallow: /api/ | ||
| Disallow: /auth/ | ||
| Disallow: /dashboard/ | ||
| Disallow: /profile/ | ||
| Disallow: /history/ | ||
| Disallow: /analyze/ | ||
| Disallow: /pr-scan/ | ||
| Disallow: /view/ | ||
|
|
||
| # Host | ||
| Host: https://codeautopsy-lyart.vercel.app | ||
|
|
||
| # Sitemaps | ||
| Sitemap: https://codeautopsy-lyart.vercel.app/sitemap.xml |
Comment on lines
+1
to
+16
| import puppeteer from "puppeteer"; | ||
| import path from "path"; | ||
| import { fileURLToPath } from "url"; | ||
|
|
||
| const __dirname = path.dirname(fileURLToPath(import.meta.url)); | ||
|
|
||
| const html = `<!DOCTYPE html><html><head><meta charset="UTF-8" /><style>* { margin: 0; padding: 0; box-sizing: border-box; } body { width: 1200px; height: 630px; overflow: hidden; background: #0e0e0e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; } .root { width: 1200px; height: 630px; background: #0e0e0e; display: flex; flex-direction: column; justify-content: center; padding: 56px 80px; position: relative; overflow: hidden; } .grid { position: absolute; inset: 0; background-image: linear-gradient(rgba(255,255,255,0.022) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.022) 1px, transparent 1px); background-size: 64px 64px; -webkit-mask-image: radial-gradient(ellipse 90% 70% at 50% 50%, black 40%, transparent 100%); pointer-events: none; } .top { display: flex; flex-direction: column; position: relative; z-index: 1; } .logo-row { display: flex; align-items: center; gap: 10px; margin-bottom: 44px; } .logo-mark { font-size: 18px; color: #e2e8f0; font-weight: 600; letter-spacing: -0.3px; } .logo-mark span { color: #334155; } .logo-sep { width: 1px; height: 16px; background: #1e293b; margin: 0 4px; } .logo-url { font-size: 13px; color: #334155; font-family: monospace; letter-spacing: 0.02em; } .eyebrow { font-size: 12px; font-weight: 600; letter-spacing: 0.18em; text-transform: uppercase; color: #334155; margin-bottom: 20px; } .headline { font-size: 76px; font-weight: 700; line-height: 1.04; letter-spacing: -3px; margin-bottom: 24px; } .headline .l1 { display: block; color: #f1f5f9; } .headline .l2 { display: block; color: #1e293b; } .sub { font-size: 17px; color: #475569; font-weight: 400; line-height: 1.5; max-width: 780px; letter-spacing: -0.2px; } .bottom { display: flex; align-items: flex-end; justify-content: space-between; position: relative; z-index: 1; } .tags { display: flex; gap: 8px; } .tag { font-size: 12px; font-weight: 500; color: #334155; border: 1px solid #1e293b; border-radius: 4px; padding: 5px 12px; letter-spacing: 0.03em; font-family: monospace; } .stats { display: flex; align-items: center; gap: 28px; } .stat { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; } .stat-val { font-size: 22px; font-weight: 700; color: #e2e8f0; letter-spacing: -0.5px; line-height: 1; } .stat-label { font-size: 11px; color: #334155; text-transform: uppercase; letter-spacing: 0.12em; font-weight: 500; } .stat-sep { width: 1px; height: 32px; background: #1e293b; }</style></head><body><div class="root"><div class="grid"></div><div class="top"><div class="logo-row"><span class="logo-mark">Code<span>Autopsy</span></span><div class="logo-sep"></div><span class="logo-url">codeautopsy-lyart.vercel.app</span></div><div class="eyebrow">AI Code Intelligence</div><div class="headline"><span class="l1">Understand any codebase</span><span class="l2">before it understands you.</span></div><div class="sub">Architecture maps · Dependency graphs · Fragile points · Execution flows</div></div><div class="bottom"><div class="tags"><div class="tag">dependency-graph</div><div class="tag">fragile-points</div><div class="tag">bridge-detection</div><div class="tag">cfg-analysis</div></div><div class="stats"><div class="stat"><span class="stat-val">75+</span><span class="stat-label">GitHub Stars</span></div><div class="stat-sep"></div><div class="stat"><span class="stat-val">1,300+</span><span class="stat-label">Clones</span></div><div class="stat-sep"></div><div class="stat"><span class="stat-val">Free</span><span class="stat-label">To Use</span></div></div></div></div></body></html>`; | ||
|
|
||
| const browser = await puppeteer.launch({ headless: true }); | ||
| const page = await browser.newPage(); | ||
| await page.setViewport({ width: 1200, height: 630, deviceScaleFactor: 2 }); | ||
| await page.setContent(html, { waitUntil: "networkidle0" }); | ||
| const outputPath = path.join(__dirname, "public", "og-image.png"); | ||
| await page.screenshot({ path: outputPath, clip: { x: 0, y: 0, width: 1200, height: 630 } }); | ||
| await browser.close(); | ||
| console.log(`OG image generated → ${outputPath}`); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.