Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

ai-review.ts

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

ai-review.tsBlame125 lines · 1 contributor
e883329Claude1/**
2 * AI-powered code review using Claude.
3 *
4 * Generates inline review comments on pull request diffs.
5 * Reviews are posted as PR comments with isAiReview=true.
6 */
7
8import Anthropic from "@anthropic-ai/sdk";
9import { config } from "./config";
10
11interface ReviewComment {
12 filePath: string;
13 lineNumber: number | null;
14 body: string;
15}
16
17interface ReviewResult {
18 summary: string;
19 comments: ReviewComment[];
20 approved: boolean;
21}
22
23let _client: Anthropic | null = null;
24
25function getClient(): Anthropic {
26 if (!_client) {
27 if (!config.anthropicApiKey) {
28 throw new Error("ANTHROPIC_API_KEY is not set");
29 }
30 _client = new Anthropic({ apiKey: config.anthropicApiKey });
31 }
32 return _client;
33}
34
35/**
36 * Run AI code review on a PR diff.
37 */
38export async function reviewDiff(
39 repoFullName: string,
40 prTitle: string,
41 prBody: string | null,
42 baseBranch: string,
43 headBranch: string,
44 diffText: string
45): Promise<ReviewResult> {
46 const client = getClient();
47
48 const message = await client.messages.create({
49 model: "claude-sonnet-4-20250514",
50 max_tokens: 4096,
51 messages: [
52 {
53 role: "user",
54 content: `You are reviewing a pull request on the repository "${repoFullName}".
55
56**PR Title:** ${prTitle}
57**PR Description:** ${prBody || "(none)"}
58**Base branch:** ${baseBranch}
59**Head branch:** ${headBranch}
60
61Review the following diff. Look for:
62- Bugs, logic errors, or potential runtime failures
63- Security vulnerabilities (injection, XSS, auth bypasses, secrets in code)
64- Performance issues (N+1 queries, unnecessary allocations, blocking I/O)
65- Missing error handling at system boundaries
66- Breaking changes or API contract violations
67
68Do NOT comment on style, formatting, naming, missing docs, or minor nitpicks. Only flag issues that could cause real problems.
69
70Respond in JSON format:
71{
72 "summary": "1-3 sentence overall assessment",
73 "approved": true/false,
74 "comments": [
75 {
76 "filePath": "path/to/file.ts",
77 "lineNumber": 42,
78 "body": "Explain the issue and suggest a fix"
79 }
80 ]
81}
82
83If the diff looks clean, return approved: true with an empty comments array.
84
85\`\`\`diff
86${diffText.slice(0, 100000)}
87\`\`\``,
88 },
89 ],
90 });
91
92 const text =
93 message.content[0].type === "text" ? message.content[0].text : "";
94
95 try {
96 // Extract JSON from response (may be wrapped in markdown code block)
97 const jsonMatch = text.match(/\{[\s\S]*\}/);
98 if (!jsonMatch) {
99 return {
100 summary: "AI review completed but could not parse structured output.",
101 comments: [],
102 approved: true,
103 };
104 }
105 const parsed = JSON.parse(jsonMatch[0]);
106 return {
107 summary: parsed.summary || "Review complete.",
108 comments: Array.isArray(parsed.comments) ? parsed.comments : [],
109 approved: parsed.approved !== false,
110 };
111 } catch {
112 return {
113 summary: text.slice(0, 500),
114 comments: [],
115 approved: true,
116 };
117 }
118}
119
120/**
121 * Check if AI review is available (API key configured).
122 */
123export function isAiReviewEnabled(): boolean {
124 return !!config.anthropicApiKey;
125}