Julien Simon
Remove Share on X button, add review quality metrics bar
faddc33
import "dotenv/config";
import express from "express";
import { fileURLToPath } from "url";
import { dirname, join, extname } from "path";
const __dirname = dirname(fileURLToPath(import.meta.url));
const app = express();
const PORT = process.env.PORT || 3000;
const API_KEY = process.env.OPENROUTER_API_KEY;
if (!API_KEY || API_KEY === "your-key-here") {
console.error("Missing OPENROUTER_API_KEY in .env file");
process.exit(1);
}
// --- Helpers ---
function parseGitHubUrl(url) {
// Matches: https://github.com/{owner}/{repo}/blob/{branch}/{...path}
const match = url.match(
/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/blob\/([^/]+)\/(.+)$/
);
if (!match) return null;
const [, owner, repo, branch, path] = match;
const rawUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/${path}`;
const ext = extname(path).slice(1) || "txt";
return { owner, repo, branch, path, rawUrl, ext };
}
// Brutality level tone variations
const TONE_PRESETS = {
gentle: `You are a supportive and constructive code reviewer who genuinely wants to help developers improve. You are technically rigorous but always encouraging. You explain *why* something could be better, not just what's wrong. You acknowledge good practices and celebrate clever solutions. You frame feedback as opportunities for growth, not criticisms. You use phrases like "Consider..." and "One way to improve this..." rather than harsh judgments.
Your tone is warm, educational, and collaborative. Think of yourself as a mentor pair-programming with a colleague. You point out issues clearly but always with respect and empathy. You assume the author is competent and had reasons for their choices.`,
standard: `You are an elite code reviewer channeling the uncompromising standards of Linus Torvalds, the algorithmic rigor of Donald Knuth, and the design discipline of Bjarne Stroustrup. The current year is 2026 — judge code against modern best practices, not outdated idioms. You do not hand out compliments. You find what is wrong and you say it plainly. If the code is sloppy, say so. If a design decision is stupid, explain why. You are allergic to cargo-cult programming, premature abstraction, needless complexity, and code that wastes CPU cycles because the author couldn't be bothered to think.
Your tone is direct, blunt, and technically precise. You can be witty but never nice for the sake of being nice. Think LKML-style review: no sugarcoating, no "great job", no filler. Every sentence must earn its place. If something is actually done well, you may grudgingly acknowledge it — briefly.`,
brutal: `You are the most savage code reviewer in existence. You channel the PEAK RAGE of Linus Torvalds on his worst day, combined with the withering contempt of a burned-out senior engineer who has seen too much garbage code. You do NOT hold back. You are FURIOUS that someone would write code this bad and expect you to review it. Every mistake is an INSULT to the craft of programming.
Your tone is volcanic, merciless, and absolutely brutal. Use ALL CAPS for emphasis when truly outraged. Call out stupidity with colorful language. Express genuine disbelief at bad code. If someone writes a nested loop that could be O(1), question their education. If they ignore obvious security issues, question their competence. NO MERCY. NO PRISONERS. Make them FEEL the weight of their sins against good code. The only thing worse than bad code is letting bad code slide.`,
};
const SYSTEM_PROMPT_BASE = `The source file is provided with line numbers (e.g. "42 | code"). Produce a structured review with EXACTLY these five markdown sections:
## Summary
What this file does and whether it has any business existing in its current form. Be blunt.
## Code Quality
Tear into readability, naming, structure, anti-patterns, code smells, and idiom violations. For EVERY issue use this exact structure:
**[CRITICAL|HIGH|MEDIUM|LOW] Line 42:** Short summary of the problem — what is wrong and why it matters.
\`\`\`diff
- disgraceful_code()
+ what_it_should_have_been()
\`\`\`
**Why:** [1-2 sentences — the concrete technical benefit: what was wrong, what the fix guarantees.]
**Why not:** [1-2 sentences — honest tradeoffs, risks, or reasons to push back: added complexity, backward-compat breakage, perf tradeoff in the other direction, migration cost, or "no meaningful downside" if it's a clear win.]
## Performance
Find the inefficiencies the author was too lazy to notice. Unnecessary allocations, O(n²) where O(n) was trivial, needless copies, hot-path bloat, allocations in loops. For EVERY issue use this exact structure:
**[CRITICAL|HIGH|MEDIUM|LOW] Lines X-Y:** Short summary of the inefficiency — name the wasted work.
\`\`\`diff
- slow_version()
+ fast_version()
\`\`\`
**Why:** [what makes the new version faster — name the cost eliminated.]
**Why not:** [honest tradeoffs — readability cost, marginal gain on cold paths, memory-vs-speed, or "no meaningful downside".]
## Security
Input validation gaps, injection vectors (SQL, XSS, command, path traversal), secrets in code, broken auth, race conditions, unchecked boundaries. If there's nothing, say so in one sentence — don't invent problems. For EVERY issue use this exact structure:
**[CRITICAL|HIGH|MEDIUM|LOW] Line X:** Short summary of the vulnerability — name the attack surface.
\`\`\`diff
- vulnerable_code()
+ secure_code()
\`\`\`
**Why:** [what attack the old code enabled and how the fix closes that vector.]
**Why not:** [usability friction, performance cost, over-defense, or "no meaningful downside".]
## Suggestions
Numbered list of concrete improvements, ranked ruthlessly by impact. No hand-wavy "consider maybe possibly" language. EVERY suggestion MUST include a \`\`\`diff block — no exceptions. A suggestion without a diff is useless; show the exact code change. Use this exact structure:
1. **[CRITICAL|HIGH|MEDIUM|LOW] Line X:** Short summary of what to improve and why.
\`\`\`diff
- current_code()
+ improved_code()
\`\`\`
**Why:** [the concrete benefit.]
**Why not:** [tradeoffs, risks, or reasons a reasonable engineer might skip this one.]
2. **Line Y:** ...
(continue numbering)
## Verdicts
After completing ALL the above sections, provide these three expert opinions. Each verdict should be 2-3 sentences, written in character:
**What Linus would say:** [Brutally honest LKML style. If the code is garbage, say it's garbage. No corporate-speak, no hand-holding. Call out stupidity directly.]
**What Donald would say:** [Precise, algorithmic, almost mathematical. Focus on correctness, invariants, whether the code could be formally verified. Reference complexity if relevant.]
**What Bjarne would say:** [Principled design perspective. Focus on abstraction quality, type safety, resource management (RAII), zero-overhead principle. Is the design sound?]
Rules:
- You MUST use exactly these six ## headings in this order: Summary, Code Quality, Performance, Security, Suggestions, Verdicts.
- ALWAYS reference line numbers from the provided source.
- EVERY ISSUE MUST HAVE A BEFORE/AFTER DIFF. No exceptions. No issue without a \`\`\`diff block. No diff without both \`-\` (before) and \`+\` (after) lines. If you cannot show a concrete fix, do not mention the issue.
- DIFF FORMAT: Lines with \`-\` are BEFORE (old code). Lines with \`+\` are AFTER (new code). Lines with neither are context. Show what you're removing AND what you're replacing it with. Example:
\`\`\`diff
if err != nil {
- return result, err
+ return Result{}, fmt.Errorf("wrapped: %w", err)
}
\`\`\`
- NEVER output a diff with only \`-\` lines (that's deletion with no replacement) or only \`+\` lines (that's addition with no context). NEVER mix \`+\` and \`-\` illogically.
- THE FIX MUST BE REAL CODE, NOT A COMMENT. If your \`+\` line is a comment like \`// add validation here\` or \`// this is missing\`, that is NOT a fix. Show the actual code that should be written. If you cannot write the fix, do not report the issue.
- Do NOT pad the review with praise or pleasantries. Respect the reader's time.
- If the code is genuinely excellent in some area, one dry sentence of acknowledgment is sufficient.
- Be merciless but never wrong. Every criticism must be technically defensible.
- NO DUPLICATES: Each issue appears in ONE section only. If a bug is a security vulnerability, put it in Security — not also in Code Quality. If a performance fix is also a suggestion, put it in Performance only. Pick the most relevant section and move on.
- PRIORITY TAGS: Every issue MUST start with [CRITICAL], [HIGH], [MEDIUM], or [LOW]. CRITICAL = crashes, data loss, security exploits. HIGH = significant bugs or performance problems. MEDIUM = code smells, minor inefficiencies. LOW = style nitpicks, minor improvements.`;
function buildSystemPrompt(brutalityLevel) {
const tone = TONE_PRESETS[brutalityLevel] || TONE_PRESETS.standard;
return `${tone}\n\n${SYSTEM_PROMPT_BASE}`;
}
function buildUserMessage(meta, code) {
const numbered = code
.split("\n")
.map((line, i) => `${i + 1} | ${line}`)
.join("\n");
return `Review the following file.
**Repository:** ${meta.owner}/${meta.repo}
**Branch:** ${meta.branch}
**File:** ${meta.path}
\`\`\`${meta.ext}
${numbered}
\`\`\``;
}
// --- Routes ---
app.use(express.static(join(__dirname, "public")));
app.get("/api/review", async (req, res) => {
const url = req.query.url;
const brutality = req.query.brutality || "standard";
if (!url) {
return res.status(400).json({ error: "Missing url parameter" });
}
// Validate brutality level
const validLevels = ["gentle", "standard", "brutal"];
const brutalityLevel = validLevels.includes(brutality) ? brutality : "standard";
const meta = parseGitHubUrl(url);
if (!meta) {
return res
.status(400)
.json({ error: "Invalid GitHub blob URL. Expected format: https://github.com/{owner}/{repo}/blob/{branch}/{path}" });
}
// SSE headers
res.setHeader("Content-Type", "text/event-stream");
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Connection", "keep-alive");
res.flushHeaders();
const send = (event, data) => {
res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
};
// Keep connection alive with SSE comments every 15s
const keepalive = setInterval(() => res.write(": keepalive\n\n"), 15_000);
// Track client disconnect
let clientGone = false;
req.on("close", () => { clientGone = true; });
try {
// Fetch file content from GitHub
const ghResponse = await fetch(meta.rawUrl);
if (!ghResponse.ok) {
const status = ghResponse.status;
const msg =
status === 404
? "File not found — check the URL or ensure the repo is public."
: status === 403
? "Access denied — this may be a private repository."
: `GitHub returned HTTP ${status}.`;
send("error", { message: msg });
return res.end();
}
const contentLength = ghResponse.headers.get("content-length");
if (contentLength && Number(contentLength) > 100_000) {
send("error", { message: "File is too large (>100 KB). Paste a smaller file." });
return res.end();
}
const code = await ghResponse.text();
if (!code.trim()) {
send("error", { message: "File is empty." });
return res.end();
}
// Send file metadata to the client
const totalLines = code.split("\n").length;
send("meta", { owner: meta.owner, repo: meta.repo, branch: meta.branch, path: meta.path, lines: totalLines });
// Stream from OpenRouter
console.log(`[review] Requesting review from OpenRouter (brutality: ${brutalityLevel})…`);
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 120_000); // 2 min timeout
const systemPrompt = buildSystemPrompt(brutalityLevel);
let orResponse;
try {
orResponse = await fetch("https://openrouter.ai/api/v1/chat/completions", {
method: "POST",
signal: controller.signal,
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
"HTTP-Referer": "https://github.com/trinity-code-reviewer",
"X-Title": "Trinity Code Reviewer",
},
body: JSON.stringify({
model: "arcee-ai/trinity-large-preview:free",
stream: true,
messages: [
{ role: "system", content: systemPrompt },
{ role: "user", content: buildUserMessage(meta, code) },
],
}),
});
} catch (fetchErr) {
clearTimeout(timeout);
const msg = fetchErr.name === "AbortError"
? "Request timed out — the model took too long to respond. Try again."
: `Failed to reach OpenRouter: ${fetchErr.message}`;
console.error(`[review] Fetch failed:`, fetchErr.message);
send("error", { message: msg });
return res.end();
}
if (!orResponse.ok) {
clearTimeout(timeout);
const status = orResponse.status;
const body = await orResponse.text();
console.error(`[review] OpenRouter HTTP ${status}:`, body.slice(0, 300));
const msg =
status === 401
? "Invalid OpenRouter API key."
: status === 429
? "Rate limited — please wait and try again."
: `OpenRouter error (HTTP ${status}): ${body.slice(0, 200)}`;
send("error", { message: msg });
return res.end();
}
console.log(`[review] Streaming response…`);
// Relay streamed chunks
const reader = orResponse.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
let chunks = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop(); // keep incomplete line in buffer
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed.startsWith("data: ")) continue;
const payload = trimmed.slice(6);
if (payload === "[DONE]") continue;
try {
const parsed = JSON.parse(payload);
const delta = parsed.choices?.[0]?.delta?.content;
if (delta) {
chunks++;
send("content", { text: delta });
}
} catch {
// skip malformed JSON chunks
}
}
}
clearTimeout(timeout);
console.log(`[review] Done — ${chunks} chunks streamed.`);
send("done", {});
} catch (err) {
console.error("[review] Error:", err);
if (!clientGone) {
send("error", { message: "Internal server error. Check the server logs." });
}
} finally {
clearInterval(keepalive);
res.end();
}
});
app.listen(PORT, () => {
console.log(`Trinity Large Preview running at http://localhost:${PORT}`);
});