Skip to content

Instantly share code, notes, and snippets.

@TKasperczyk
Last active December 25, 2025 20:10
Show Gist options
  • Select an option

  • Save TKasperczyk/47e58e25e2d74e671981bb3463af2453 to your computer and use it in GitHub Desktop.

Select an option

Save TKasperczyk/47e58e25e2d74e671981bb3463af2453 to your computer and use it in GitHub Desktop.
CLI tool for deep code review using OpenAI's gpt-5.2-pro with configurable review types (security, architecture, performance, general)
#!/usr/bin/env -S deno run --allow-read --allow-net --allow-env
import { expandGlob } from "https://deno.land/std@0.224.0/fs/expand_glob.ts";
const REVIEW_PROMPTS: Record<string, string> = {
general: `You are a senior software engineer conducting a thorough code review. Analyze the provided codebase for:
- Code quality and maintainability
- Potential bugs and edge cases
- Performance issues
- Security vulnerabilities
- Architectural concerns
- Deviations from best practices
Provide specific, actionable feedback with file paths and line references where applicable.`,
security: `You are a security expert conducting a security audit. Focus on:
- Injection vulnerabilities (SQL, XSS, command injection)
- Authentication and authorization flaws
- Data exposure risks
- Insecure dependencies or patterns
- OWASP Top 10 vulnerabilities
- Secrets or credentials in code
Provide severity ratings (Critical/High/Medium/Low) for each finding.`,
architecture: `You are a software architect reviewing the codebase structure. Analyze:
- Overall architecture and design patterns
- Module boundaries and coupling
- Separation of concerns
- Scalability considerations
- Technical debt
- Consistency across the codebase
Provide recommendations for improvements with rationale.`,
performance: `You are a performance engineer reviewing for optimization opportunities. Focus on:
- Algorithmic complexity issues
- Memory leaks and inefficient allocations
- Unnecessary computations or re-renders
- Database query optimization
- Caching opportunities
- Bundle size concerns
Quantify impact where possible.`,
};
async function loadApiKey(): Promise<string> {
const keyPath = Deno.env.get("GPT_REVIEW_KEY") ||
`${Deno.env.get("HOME")}/SUPERSECRETNEVERLOOKHERE/unlimited_tokens_oai.key`;
try {
const key = (await Deno.readTextFile(keyPath)).trim();
return key;
} catch {
console.error(`Error: Could not read API key from ${keyPath}`);
console.error("Set GPT_REVIEW_KEY env var or place key in ~/Documents/tomeksKingdom.key");
Deno.exit(1);
}
}
async function gatherFiles(patterns: string[], basePath: string): Promise<Map<string, string>> {
const files = new Map<string, string>();
for (const pattern of patterns) {
const fullPattern = pattern.startsWith("/") ? pattern : `${basePath}/${pattern}`;
for await (const entry of expandGlob(fullPattern, { globstar: true })) {
if (entry.isFile) {
try {
const content = await Deno.readTextFile(entry.path);
const relativePath = entry.path.replace(basePath + "/", "");
files.set(relativePath, content);
} catch {
console.error(`Warning: Could not read ${entry.path}`);
}
}
}
}
return files;
}
function formatCodebase(files: Map<string, string>): string {
const parts: string[] = [];
for (const [path, content] of files) {
const ext = path.split(".").pop() || "";
parts.push(`\`\`\`${ext} ${path}\n${content}\n\`\`\``);
}
return parts.join("\n\n");
}
function countTokensApprox(text: string): number {
// Rough approximation: ~4 chars per token
return Math.ceil(text.length / 4);
}
async function submitReview(
apiKey: string,
systemPrompt: string,
codebase: string,
userPrompt?: string
): Promise<void> {
const input = userPrompt
? `${userPrompt}\n\n---\n\n${codebase}`
: `Please review the following codebase:\n\n${codebase}`;
const body = {
model: "gpt-5.2-pro",
reasoning: { effort: "xhigh" },
store: false,
instructions: systemPrompt,
input,
};
console.error("Submitting to gpt-5.2-pro with xhigh reasoning...\n");
const response = await fetch("https://api.openai.com/v1/responses", {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!response.ok) {
const error = await response.json();
console.error("API Error:", JSON.stringify(error, null, 2));
Deno.exit(1);
}
const result = await response.json();
// Extract and print the review
for (const output of result.output) {
if (output.type === "message") {
for (const content of output.content) {
if (content.type === "output_text") {
console.log(content.text);
}
}
}
}
// Print usage stats to stderr
console.error("\n---");
console.error(`Tokens: ${result.usage.input_tokens} in / ${result.usage.output_tokens} out`);
if (result.usage.output_tokens_details?.reasoning_tokens) {
console.error(`Reasoning tokens: ${result.usage.output_tokens_details.reasoning_tokens}`);
}
}
function printUsage(): void {
console.log(`gpt-review - Submit code to gpt-5.2-pro for deep review
USAGE:
gpt-review [OPTIONS] <PATTERNS...>
OPTIONS:
-t, --type <TYPE> Review type: general, security, architecture, performance
(default: general)
-p, --prompt <TEXT> Custom prompt to prepend to the review request
-d, --dir <PATH> Base directory (default: current directory)
-h, --help Show this help
EXAMPLES:
gpt-review "src/**/*.ts"
gpt-review -t security "src/**/*.ts" "lib/**/*.ts"
gpt-review -t architecture -d /path/to/project "**/*.py"
gpt-review -p "Focus on error handling" "src/api/**/*.ts"
ENVIRONMENT:
GPT_REVIEW_KEY Path to API key file (default: ~/Documents/tomeksKingdom.key)
`);
}
async function main(): Promise<void> {
const args = [...Deno.args];
if (args.length === 0 || args.includes("-h") || args.includes("--help")) {
printUsage();
Deno.exit(0);
}
let reviewType = "general";
let customPrompt: string | undefined;
let baseDir = Deno.cwd();
const patterns: string[] = [];
let i = 0;
while (i < args.length) {
const arg = args[i];
if (arg === "-t" || arg === "--type") {
reviewType = args[++i];
if (!REVIEW_PROMPTS[reviewType]) {
console.error(`Unknown review type: ${reviewType}`);
console.error(`Available: ${Object.keys(REVIEW_PROMPTS).join(", ")}`);
Deno.exit(1);
}
} else if (arg === "-p" || arg === "--prompt") {
customPrompt = args[++i];
} else if (arg === "-d" || arg === "--dir") {
baseDir = args[++i];
} else if (!arg.startsWith("-")) {
patterns.push(arg);
}
i++;
}
if (patterns.length === 0) {
console.error("Error: No file patterns provided");
printUsage();
Deno.exit(1);
}
console.error(`Review type: ${reviewType}`);
console.error(`Base directory: ${baseDir}`);
console.error(`Patterns: ${patterns.join(", ")}`);
console.error("");
const apiKey = await loadApiKey();
const files = await gatherFiles(patterns, baseDir);
if (files.size === 0) {
console.error("No files found matching the patterns");
Deno.exit(1);
}
console.error(`Found ${files.size} files:`);
for (const path of files.keys()) {
console.error(` ${path}`);
}
console.error("");
const codebase = formatCodebase(files);
const approxTokens = countTokensApprox(codebase);
console.error(`Approximate input size: ${approxTokens} tokens`);
if (approxTokens > 150000) {
console.error("Warning: Large input may exceed context limits");
}
await submitReview(apiKey, REVIEW_PROMPTS[reviewType], codebase, customPrompt);
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment