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 +350 -0
- package/bin/cli.js +190 -0
- package/bin/dashboard.js +505 -0
- package/bin/install.js +111 -0
- package/bin/uninstall.js +44 -0
- package/package.json +58 -0
- package/src/analyzer/api.js +197 -0
- package/src/analyzer/git.js +158 -0
- package/src/analyzer/prompt.js +408 -0
- package/src/config.js +93 -0
- package/src/index.js +94 -0
- package/src/memory/index.js +101 -0
- package/src/output/colors.js +85 -0
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
|
+
[](https://www.npmjs.com/package/ai-senior-dev-reviewer)
|
|
10
|
+
[](https://opensource.org/licenses/MIT)
|
|
11
|
+
[](https://nodejs.org)
|
|
12
|
+
[](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
|
+
}
|