ai-commit-reviewer 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,350 @@
1
+ <div align="center">
2
+
3
+ # 🔍 AI Senior Dev Reviewer
4
+
5
+ **The AI code reviewer that thinks like a senior React Native & Next.js engineer.**
6
+
7
+ Runs on every `git commit`. Catches crashes, ANRs, hydration errors, security holes, and bad patterns before they hit production. Gets smarter with every commit by learning your team's specific blind spots.
8
+
9
+ [![npm version](https://img.shields.io/npm/v/ai-senior-dev-reviewer.svg)](https://www.npmjs.com/package/ai-senior-dev-reviewer)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
11
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D16.0.0-brightgreen)](https://nodejs.org)
12
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)
13
+
14
+ [Installation](#installation) · [What it catches](#what-it-catches) · [Self-improving memory](#self-improving-memory) · [Commands](#commands) · [Config](#configuration) · [vs other tools](#why-not-just-use-copilot)
15
+
16
+ </div>
17
+
18
+ ---
19
+
20
+ ## The problem
21
+
22
+ You write code. You commit. You push. A senior dev reviews your PR two days later and finds a null dereference crash, a hardcoded API key, and a component that already exists in the codebase.
23
+
24
+ **That feedback loop is too slow and too late.**
25
+
26
+ AI Senior Dev Reviewer runs at `git commit` — before the code ever leaves your machine. It blocks the commit if it finds something serious, and explains exactly how to fix it.
27
+
28
+ ```
29
+ git commit -m "payment success revamp"
30
+
31
+ ╔══════════════════════════════════════════╗
32
+ ║ AI Senior Dev Reviewer ║
33
+ ╚══════════════════════════════════════════╝
34
+
35
+ Files staged: 1
36
+ Reviews done: 24
37
+ Known blind spots: missing useCallback on handlers · AsyncStorage for tokens
38
+
39
+ Building codebase snapshot...
40
+ Sending to AI...
41
+
42
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
43
+
44
+ PASS 1 — SECURITY
45
+
46
+ 🔴 BLOCK [SECURITY] containers/Payment/index.tsx:42
47
+ Problem: Auth token stored in AsyncStorage — unencrypted plaintext on disk
48
+ Risk: Device theft or backup extraction exposes the token permanently
49
+ Fix:
50
+ // Before
51
+ await AsyncStorage.setItem('token', userToken)
52
+
53
+ // After
54
+ import * as Keychain from 'react-native-keychain'
55
+ await Keychain.setGenericPassword('token', userToken)
56
+
57
+ PASS 2 — CRASHES
58
+
59
+ 🔴 BLOCK [CRASH] containers/Payment/index.tsx:87
60
+ Problem: route.params.orderId accessed without existence check
61
+ Risk: Navigating to this screen without params crashes the app instantly
62
+ Fix:
63
+ // Before
64
+ const { orderId } = route.params
65
+
66
+ // After
67
+ const { orderId } = route.params ?? {}
68
+ if (!orderId) return <ErrorScreen />
69
+
70
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
71
+
72
+ ✗ Commit BLOCKED — fix the 🔴 BLOCK issues above first
73
+ Most critical: Auth token stored unencrypted in AsyncStorage
74
+ To skip (use sparingly): git commit --no-verify
75
+ ```
76
+
77
+ ---
78
+
79
+ ## What it catches
80
+
81
+ ### 9 review passes on every commit
82
+
83
+ | Pass | Category | Examples |
84
+ |------|----------|---------|
85
+ | 1 | **Security** | Hardcoded secrets, unencrypted token storage, missing API auth, XSS, SQL injection |
86
+ | 2 | **Crashes** | Null deref, unhandled rejections, infinite loops, FlatList-in-ScrollView, missing cleanup |
87
+ | 3 | **ANRs & Perf** | JS thread blocking, missing memo, O(n²) loops, no debounce, ScrollView for large lists |
88
+ | 4 | **Hydration** | Server/client mismatch, window in SSR, useLayoutEffect, invalid HTML nesting, dynamic() missing |
89
+ | 5 | **Next.js** | Missing auth on API routes, Server/Client component misuse, redirect() in try/catch, missing Suspense |
90
+ | 6 | **Better code** | 40-line functions, nested ternaries, no early returns, sequential awaits |
91
+ | 7 | **Duplicates** | Component already exists, util already in utils/, hook already extracted |
92
+ | 8 | **Non-fatals** | Race conditions, double form submit, stale closures, network errors swallowed |
93
+ | 9 | **Style** | Vague names, magic numbers, dead code, missing boolean predicates |
94
+
95
+ ### Framework-aware
96
+
97
+ Automatically detects which framework you're using and applies the right checks:
98
+
99
+ **React Native** — ANR risks, JS bridge overload, `useNativeDriver`, `FlatList` vs `ScrollView`, `Platform.OS` guards, permission checks, `react-native-keychain`, `react-native-fast-image`
100
+
101
+ **Next.js** — Hydration mismatches, Server vs Client component misuse, `redirect()` gotchas, `useSearchParams` without Suspense, missing `loading.tsx` / `error.tsx`, ISR revalidation, `next/image`, `next/font`
102
+
103
+ **React web** — Bundle splitting, virtualisation, error boundaries, SSR guards, `dangerouslySetInnerHTML`
104
+
105
+ ---
106
+
107
+ ## Self-improving memory
108
+
109
+ This is what makes it different from every other tool.
110
+
111
+ After every review, it writes to `.ai-reviewer/patterns.json` in your project:
112
+
113
+ ```json
114
+ {
115
+ "total_commits_reviewed": 47,
116
+ "team_blind_spots": [
117
+ "missing useCallback on handlers passed to memoized children",
118
+ "AsyncStorage used for auth tokens instead of Keychain",
119
+ "no optional chaining on navigation route.params",
120
+ "inline style objects created in JSX instead of StyleSheet"
121
+ ]
122
+ }
123
+ ```
124
+
125
+ Every future review starts with: *"this team has historically gotten these things wrong — pay extra attention."*
126
+
127
+ After 10 commits it knows your codebase. After 50 it knows your team.
128
+
129
+ **Commit `patterns.json` to git** — the whole team shares the learned memory.
130
+
131
+ ---
132
+
133
+ ## Why not just use Copilot?
134
+
135
+ | | GitHub Copilot | CodeRabbit | ESLint | **This tool** |
136
+ |--|:-:|:-:|:-:|:-:|
137
+ | Blocks bad commits | ✗ | ✗ | ✗ | ✓ |
138
+ | React Native crash detection | ✗ | ✗ | ✗ | ✓ |
139
+ | ANR detection | ✗ | ✗ | ✗ | ✓ |
140
+ | Hydration error detection | ✗ | ✗ | ✗ | ✓ |
141
+ | Self-improving memory | ✗ | ✗ | ✗ | ✓ |
142
+ | Duplicate component detection | ✗ | partial | ✗ | ✓ |
143
+ | Works at commit time | ✗ | ✗ (PR only) | ✓ | ✓ |
144
+ | Before/after code fixes | ✗ | partial | ✗ | ✓ |
145
+ | Zero infrastructure | ✓ | ✗ | ✓ | ✓ |
146
+ | Cost | $19/dev/mo | $19/dev/mo | free | ~$5 total |
147
+
148
+ **Copilot** helps you write code faster. This tool stops bad code reaching the repo.
149
+
150
+ **CodeRabbit** reviews PRs after bad code is already in the branch. This tool catches it before it's committed.
151
+
152
+ **ESLint** catches syntax and rule violations. This tool catches intent, logic bugs, and production failure patterns.
153
+
154
+ ---
155
+
156
+ ## Installation
157
+
158
+ ### Requirements
159
+ - Node.js 16+
160
+ - Git
161
+ - An API key (OpenAI, Anthropic, or Google Gemini)
162
+
163
+ ### Global install (works across all your projects)
164
+
165
+ ```bash
166
+ # Clone somewhere permanent
167
+ git clone https://github.com/your-username/ai-senior-dev-reviewer.git ~/tools/ai-reviewer
168
+ cd ~/tools/ai-reviewer
169
+ npm link
170
+ ```
171
+
172
+ Or install from npm:
173
+ ```bash
174
+ npm install -g ai-senior-dev-reviewer
175
+ ```
176
+
177
+ ### Per-project setup
178
+
179
+ ```bash
180
+ # Go to your project
181
+ cd your-project
182
+
183
+ # Create .env with your API key (never commit this)
184
+ echo 'OPENAI_API_KEY=sk-proj-...' > .env
185
+ echo '.env' >> .gitignore
186
+
187
+ # Install the git hook
188
+ ai-reviewer install
189
+
190
+ # Verify everything is set up
191
+ ai-reviewer status
192
+ ```
193
+
194
+ Done. The reviewer fires automatically on every `git commit`.
195
+
196
+ ### Monorepo setup
197
+
198
+ Works perfectly in monorepos — each sub-project gets its own scoped hook and its own memory:
199
+
200
+ ```bash
201
+ cd myrepo/nextjs && ai-reviewer install
202
+ cd myrepo/mobile && ai-reviewer install
203
+ cd myrepo/pos && ai-reviewer install
204
+ ```
205
+
206
+ ---
207
+
208
+ ## API keys
209
+
210
+ The tool supports three providers. Add one to your project's `.env`:
211
+
212
+ ```bash
213
+ # Option 1 — OpenAI (most reliable)
214
+ OPENAI_API_KEY=sk-proj-...
215
+ AI_REVIEWER_MODEL=gpt-4o-mini # ~$0.003/review
216
+
217
+ # Option 2 — Anthropic ($5 free credits)
218
+ ANTHROPIC_API_KEY=sk-ant-...
219
+ # uses claude-3-5-haiku by default
220
+
221
+ # Option 3 — Google Gemini (free tier available)
222
+ GEMINI_API_KEY=AIza...
223
+ # uses gemini-1.5-flash by default
224
+ ```
225
+
226
+ Priority: **Anthropic → Gemini → OpenAI** (whichever key is present).
227
+
228
+ ### Cost comparison
229
+
230
+ | Provider | Model | Cost per review | $5 buys you |
231
+ |----------|-------|----------------|-------------|
232
+ | OpenAI | gpt-4o-mini | ~$0.003 | ~1,600 reviews |
233
+ | OpenAI | gpt-4o | ~$0.04 | ~125 reviews |
234
+ | Anthropic | claude-3-5-haiku | ~$0.001 | ~5,000 reviews |
235
+ | Gemini | gemini-1.5-flash | free tier | free |
236
+
237
+ ---
238
+
239
+ ## Commands
240
+
241
+ ```bash
242
+ ai-reviewer install # install hook into current project
243
+ ai-reviewer uninstall # remove hook (restores backup if exists)
244
+ ai-reviewer review # run manually on staged files
245
+ ai-reviewer dashboard # open HTML review history in browser
246
+ ai-reviewer status # show hook status, API key, patterns learned
247
+ ai-reviewer help # show all commands
248
+
249
+ # Skip review for one commit
250
+ git commit --no-verify
251
+ ```
252
+
253
+ ---
254
+
255
+ ## Configuration
256
+
257
+ All settings can be overridden via environment variables or by editing `src/config.js`:
258
+
259
+ | Variable | Default | Description |
260
+ |----------|---------|-------------|
261
+ | `OPENAI_API_KEY` | — | OpenAI API key |
262
+ | `ANTHROPIC_API_KEY` | — | Anthropic API key |
263
+ | `GEMINI_API_KEY` | — | Google Gemini API key |
264
+ | `AI_REVIEWER_MODEL` | auto | Override the model (e.g. `gpt-4o`, `claude-3-5-sonnet-20241022`) |
265
+ | `AI_REVIEWER_VERBOSE` | false | Show provider, model, env path info |
266
+
267
+ ---
268
+
269
+ ## Severity levels
270
+
271
+ | | Level | Behaviour |
272
+ |--|-------|-----------|
273
+ | 🔴 | **BLOCK** | Security vulnerability or crash/ANR risk — commit is rejected |
274
+ | 🟡 | **WARN** | Performance or logic bug — commit allowed, fix before merging |
275
+ | 🔵 | **SUGGEST** | Better way to write it — educational, non-blocking |
276
+ | ⚪ | **STYLE** | Naming, dead code, readability — non-blocking |
277
+
278
+ ---
279
+
280
+ ## Project structure
281
+
282
+ ```
283
+ ai-senior-dev-reviewer/
284
+ ├── src/
285
+ │ ├── index.js — main orchestrator
286
+ │ ├── config.js — configuration + env loading
287
+ │ ├── analyzer/
288
+ │ │ ├── git.js — staged files, diff, codebase snapshot
289
+ │ │ ├── prompt.js — 9-pass review prompt
290
+ │ │ └── api.js — multi-provider AI client (OpenAI/Anthropic/Gemini)
291
+ │ ├── memory/
292
+ │ │ └── index.js — patterns.json, blind spots, audit log
293
+ │ └── output/
294
+ │ └── colors.js — terminal colour output
295
+ ├── bin/
296
+ │ ├── cli.js — global CLI entry point
297
+ │ ├── install.js — scoped git hook installer
298
+ │ ├── uninstall.js — hook removal with backup restore
299
+ │ └── dashboard.js — HTML review history generator
300
+ └── .ai-reviewer/ — auto-created per project
301
+ ├── patterns.json — learned team patterns ← commit this
302
+ ├── codebase-context.json — component inventory ← commit this
303
+ ├── review-log.jsonl — audit log ← gitignore this
304
+ └── dashboard.html — generated report ← gitignore this
305
+ ```
306
+
307
+ ---
308
+
309
+ ## .gitignore recommendation
310
+
311
+ ```gitignore
312
+ # Never commit
313
+ .env
314
+ .ai-reviewer/review-log.jsonl
315
+ .ai-reviewer/dashboard.html
316
+
317
+ # DO commit — shared team memory
318
+ # .ai-reviewer/patterns.json
319
+ # .ai-reviewer/codebase-context.json
320
+ ```
321
+
322
+ ---
323
+
324
+ ## Contributing
325
+
326
+ PRs welcome. Main areas to improve:
327
+
328
+ - More framework-specific checks (Vue, Svelte, Expo Router)
329
+ - VS Code extension to show issues inline
330
+ - GitHub Actions integration for CI
331
+ - Support for more AI providers (Mistral, Ollama for local models)
332
+ - Configurable severity rules per project
333
+
334
+ See [CONTRIBUTING.md](CONTRIBUTING.md) to get started.
335
+
336
+ ---
337
+
338
+ ## License
339
+
340
+ MIT — use it, fork it, improve it.
341
+
342
+ ---
343
+
344
+ <div align="center">
345
+
346
+ Built by a developer who got tired of catching the same bugs in code review.
347
+
348
+ **Star it if it saves you from a production crash. ⭐**
349
+
350
+ </div>
package/bin/cli.js ADDED
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env node
2
+ // ── bin/cli.js ────────────────────────────────────────────
3
+
4
+ const path = require("path");
5
+ const fs = require("fs");
6
+ const { execSync } = require("child_process");
7
+
8
+ const C = {
9
+ red: "\x1b[31m",
10
+ yellow: "\x1b[33m",
11
+ blue: "\x1b[34m",
12
+ green: "\x1b[32m",
13
+ cyan: "\x1b[36m",
14
+ bold: "\x1b[1m",
15
+ dim: "\x1b[2m",
16
+ reset: "\x1b[0m",
17
+ };
18
+
19
+ const cmd = process.argv[2];
20
+
21
+ function run(c) {
22
+ try {
23
+ return execSync(c, {
24
+ encoding: "utf8",
25
+ stdio: ["pipe", "pipe", "pipe"],
26
+ }).trim();
27
+ } catch {
28
+ return "";
29
+ }
30
+ }
31
+
32
+ // ── Help ──────────────────────────────────────────────────
33
+ function showHelp() {
34
+ console.log(`
35
+ ${C.bold}${C.cyan} AI Senior Dev Reviewer${C.reset}
36
+ Self-improving code reviewer for React & React Native
37
+
38
+ ${C.bold} Usage:${C.reset}
39
+ ${C.green}ai-reviewer install${C.reset} Install hook scoped to current sub-project
40
+ ${C.green}ai-reviewer uninstall${C.reset} Remove hook
41
+ ${C.green}ai-reviewer review${C.reset} Run manually on staged files
42
+ ${C.green}ai-reviewer dashboard${C.reset} Open review history dashboard
43
+ ${C.green}ai-reviewer status${C.reset} Show project status
44
+ ${C.green}ai-reviewer help${C.reset} Show this help
45
+
46
+ ${C.bold} Monorepo example:${C.reset}
47
+ cd newmecode/nextjs && ai-reviewer install
48
+ cd newmecode/mobile && ai-reviewer install
49
+ cd newmecode/pos && ai-reviewer install
50
+
51
+ Each sub-project gets its own scoped hook + its own memory.
52
+
53
+ ${C.bold} Skip a review:${C.reset}
54
+ git commit --no-verify
55
+ `);
56
+ }
57
+
58
+ // ── Status ────────────────────────────────────────────────
59
+ function showStatus() {
60
+ const gitRoot = run("git rev-parse --show-toplevel");
61
+ const projectDir = process.cwd();
62
+ const projectName = path.basename(projectDir);
63
+
64
+ if (!gitRoot) {
65
+ console.log(`${C.red}✗ Not inside a git repository${C.reset}`);
66
+ return;
67
+ }
68
+
69
+ const hookPath = path.join(gitRoot, ".git", "hooks", "pre-commit");
70
+ const hookContent = fs.existsSync(hookPath)
71
+ ? fs.readFileSync(hookPath, "utf8")
72
+ : "";
73
+
74
+ // Check hook is scoped to THIS sub-project
75
+ const hookInstalled =
76
+ hookContent.includes("AI Senior Dev Reviewer") &&
77
+ hookContent.includes(projectDir);
78
+
79
+ const patternsPath = path.join(projectDir, ".ai-reviewer", "patterns.json");
80
+ let patterns = {};
81
+ try {
82
+ patterns = JSON.parse(fs.readFileSync(patternsPath, "utf8"));
83
+ } catch {}
84
+
85
+ // Load env to check API key
86
+ const envPath = path.join(projectDir, ".env");
87
+ let apiKeyInEnv = false;
88
+ if (fs.existsSync(envPath)) {
89
+ const envContent = fs.readFileSync(envPath, "utf8");
90
+ apiKeyInEnv =
91
+ envContent.includes("GEMINI_API_KEY") ||
92
+ envContent.includes("ANTHROPIC_API_KEY") ||
93
+ envContent.includes("OPENAI_API_KEY");
94
+ }
95
+ const apiKey = process.env.OPENAI_API_KEY || apiKeyInEnv;
96
+ const model = process.env.AI_REVIEWER_MODEL || "gpt-4o-mini";
97
+
98
+ console.log(`\n${C.bold}${C.cyan} AI Reviewer — Project Status${C.reset}\n`);
99
+ console.log(` Sub-project: ${C.bold}${projectName}${C.reset}`);
100
+ console.log(` Path: ${C.dim}${projectDir}${C.reset}`);
101
+ console.log(` Git root: ${C.dim}${gitRoot}${C.reset}`);
102
+ console.log(
103
+ ` Hook: ${
104
+ hookInstalled
105
+ ? `${C.green}✓ installed (scoped to ${projectName})${C.reset}`
106
+ : `${C.red}✗ not installed${C.reset} — run: ai-reviewer install`
107
+ }`,
108
+ );
109
+ console.log(
110
+ ` API key: ${
111
+ apiKey
112
+ ? `${C.green}✓ set${C.reset}`
113
+ : `${C.red}✗ missing${C.reset} — add GEMINI_API_KEY / ANTHROPIC_API_KEY / OPENAI_API_KEY to ${projectName}/.env`
114
+ }`,
115
+ );
116
+ console.log(
117
+ ` .env: ${
118
+ fs.existsSync(envPath)
119
+ ? `${C.green}✓ found${C.reset} (${envPath})`
120
+ : `${C.yellow}✗ no .env found${C.reset}`
121
+ }`,
122
+ );
123
+ console.log(` Model: ${C.cyan}${model}${C.reset}`);
124
+ console.log(
125
+ ` Reviews done: ${C.bold}${patterns.total_commits_reviewed || 0}${C.reset}`,
126
+ );
127
+ console.log(
128
+ ` Patterns: ${C.bold}${patterns.recurring_issues?.length || 0}${C.reset} learned`,
129
+ );
130
+
131
+ if (patterns.team_blind_spots?.length) {
132
+ console.log(
133
+ `\n ${C.yellow}${C.bold}Team blind spots for ${projectName}:${C.reset}`,
134
+ );
135
+ patterns.team_blind_spots.forEach((s, i) => {
136
+ console.log(` ${C.dim}${i + 1}.${C.reset} ${s}`);
137
+ });
138
+ }
139
+ console.log("");
140
+ }
141
+
142
+ // ── Open dashboard ────────────────────────────────────────
143
+ function openDashboard() {
144
+ require("./dashboard.js");
145
+ const dashPath = path.join(process.cwd(), ".ai-reviewer", "dashboard.html");
146
+ setTimeout(() => {
147
+ if (fs.existsSync(dashPath)) {
148
+ const opener =
149
+ process.platform === "darwin"
150
+ ? "open"
151
+ : process.platform === "win32"
152
+ ? "start"
153
+ : "xdg-open";
154
+ try {
155
+ execSync(`${opener} "${dashPath}"`);
156
+ } catch {
157
+ console.log(` Open manually: ${dashPath}`);
158
+ }
159
+ }
160
+ }, 300);
161
+ }
162
+
163
+ // ── Route ─────────────────────────────────────────────────
164
+ switch (cmd) {
165
+ case "install":
166
+ require("./install.js");
167
+ break;
168
+ case "uninstall":
169
+ require("./uninstall.js");
170
+ break;
171
+ case "review":
172
+ require("../src/index.js");
173
+ break;
174
+ case "dashboard":
175
+ openDashboard();
176
+ break;
177
+ case "status":
178
+ showStatus();
179
+ break;
180
+ case "help":
181
+ case "--help":
182
+ case "-h":
183
+ case undefined:
184
+ showHelp();
185
+ break;
186
+ default:
187
+ console.log(`${C.red}Unknown command: ${cmd}${C.reset}`);
188
+ showHelp();
189
+ process.exit(1);
190
+ }