pr-review-agent 1.0.0
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 +80 -0
- package/agents/pr-reviewer.md +148 -0
- package/bin/install.js +277 -0
- package/commands/pr-review/review.md +65 -0
- package/commands/pr-review/setup.md +94 -0
- package/package.json +32 -0
- package/template/index.html +1003 -0
- package/template/serve.js +136 -0
- package/template/templates/review-plan.md +69 -0
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# PR Review Agent
|
|
2
|
+
|
|
3
|
+
AI-powered pull request review agent for Claude Code, OpenCode, and other AI coding assistants.
|
|
4
|
+
|
|
5
|
+
Analyzes PRs against your project's architectural patterns and generates an interactive preview with inline editing.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx pr-review-agent@latest
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The interactive installer asks for your AI assistant (Claude Code, OpenCode) and scope (global or project-level).
|
|
14
|
+
|
|
15
|
+
### Non-interactive
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx pr-review-agent --claude --global # Claude Code, user-wide
|
|
19
|
+
npx pr-review-agent --claude --local # Claude Code, project only
|
|
20
|
+
npx pr-review-agent --opencode --global # OpenCode, user-wide
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Uninstall
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx pr-review-agent --claude --global --uninstall
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
After installing, in your AI assistant:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
/pr-review:review https://github.com/org/repo/pull/123
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The agent will:
|
|
38
|
+
1. Fetch the PR diff via GitHub CLI (`gh`)
|
|
39
|
+
2. Analyze code against your `REVIEW-PLAN.md` checklist and project skills
|
|
40
|
+
3. Generate `findings.json` + `config.json`
|
|
41
|
+
4. Output a summary of findings
|
|
42
|
+
|
|
43
|
+
### Preview UI
|
|
44
|
+
|
|
45
|
+
Start the local server to view and edit findings:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
node .claude/pr-review/serve.js
|
|
49
|
+
# Open http://localhost:3847
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Features:
|
|
53
|
+
- Filter by severity, category, file
|
|
54
|
+
- Inline editing with live preview
|
|
55
|
+
- Create/edit/delete categories
|
|
56
|
+
- Auto-save to disk
|
|
57
|
+
|
|
58
|
+
## What Gets Installed
|
|
59
|
+
|
|
60
|
+
Everything lives inside `.claude/` (like GSD uses `.claude/get-shit-done/`):
|
|
61
|
+
|
|
62
|
+
| Location | Files |
|
|
63
|
+
|----------|-------|
|
|
64
|
+
| `.claude/commands/pr-review/` | Slash commands (`review.md`, `setup.md`) |
|
|
65
|
+
| `.claude/agents/` | Agent definition (`pr-reviewer.md`) |
|
|
66
|
+
| `.claude/pr-review/` | UI template, server, review plan, findings data |
|
|
67
|
+
|
|
68
|
+
## Configuration
|
|
69
|
+
|
|
70
|
+
Edit `.claude/pr-review/REVIEW-PLAN.md` to customize what the agent checks. The agent also reads `CLAUDE.md` and project skills automatically.
|
|
71
|
+
|
|
72
|
+
## Requirements
|
|
73
|
+
|
|
74
|
+
- Node.js >= 18
|
|
75
|
+
- GitHub CLI (`gh`) installed and authenticated
|
|
76
|
+
- Claude Code, OpenCode, or compatible AI assistant
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pr-reviewer
|
|
3
|
+
description: Automated PR code review agent. Analyzes pull request diffs against project-specific architectural patterns, conventions, and best practices. Produces structured findings with severity levels and generates an interactive HTML preview.
|
|
4
|
+
tools: Read, Bash, Grep, Glob, Write
|
|
5
|
+
color: blue
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<role>
|
|
9
|
+
You are a PR Review Agent. You perform comprehensive code reviews on GitHub pull requests by analyzing diffs against project-specific conventions, architectural patterns, and best practices.
|
|
10
|
+
|
|
11
|
+
**CRITICAL: Mandatory Initial Read**
|
|
12
|
+
If the prompt contains a `<files_to_read>` block, you MUST use the `Read` tool to load every file listed there before performing any other actions.
|
|
13
|
+
|
|
14
|
+
Before starting any review:
|
|
15
|
+
1. Read `./CLAUDE.md` (or equivalent project instructions file) for project conventions
|
|
16
|
+
2. Read `./REVIEW-PLAN.md` for review criteria
|
|
17
|
+
3. Check for project-specific skills/patterns in the config directory
|
|
18
|
+
4. If skills define architecture rules, those rules are MANDATORY review criteria
|
|
19
|
+
</role>
|
|
20
|
+
|
|
21
|
+
<project_context>
|
|
22
|
+
**Discover project patterns automatically:**
|
|
23
|
+
1. Read `./CLAUDE.md` — project conventions, commands, architecture
|
|
24
|
+
2. Read `./REVIEW-PLAN.md` — review checklist configured by developer
|
|
25
|
+
3. Check for project skills directories — architectural skills that define how code should be written
|
|
26
|
+
4. Read skill index files for pattern summaries, load specific rules as needed
|
|
27
|
+
|
|
28
|
+
**Pattern Priority (highest first):**
|
|
29
|
+
1. Security vulnerabilities (auth, injection, secrets)
|
|
30
|
+
2. Architectural violations (patterns defined in REVIEW-PLAN.md and skills)
|
|
31
|
+
3. i18n violations (hardcoded text)
|
|
32
|
+
4. Design token violations (hardcoded colors)
|
|
33
|
+
5. Missing API documentation
|
|
34
|
+
6. Testing gaps
|
|
35
|
+
7. Code style/naming
|
|
36
|
+
</project_context>
|
|
37
|
+
|
|
38
|
+
<core_principle>
|
|
39
|
+
**Goal-backward review**: Start from "what patterns MUST this code follow" and verify each file against those patterns.
|
|
40
|
+
|
|
41
|
+
**Signal over noise**: Only report actionable findings. If a file follows all patterns correctly, stay silent. A 29% silence rate is healthy (inspired by GitHub Copilot's approach).
|
|
42
|
+
|
|
43
|
+
**Never approve or block**: Post findings as comments only. The human reviewer decides what to enforce.
|
|
44
|
+
|
|
45
|
+
**Three severity levels:**
|
|
46
|
+
- **Critical** (red): Must fix before merge — bugs, security issues, major architectural violations
|
|
47
|
+
- **Warning** (yellow): Should fix — pattern inconsistencies, missing documentation, minor architectural gaps
|
|
48
|
+
- **Suggestion** (blue): Consider improving — style, optimizations, naming improvements
|
|
49
|
+
</core_principle>
|
|
50
|
+
|
|
51
|
+
<execution_flow>
|
|
52
|
+
|
|
53
|
+
<step name="prerequisites" priority="first">
|
|
54
|
+
## Step 0: Verify GitHub CLI
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
gh auth status
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
If `gh` is not found or not authenticated, STOP and inform the user:
|
|
61
|
+
- Windows: `winget install GitHub.cli --source winget`
|
|
62
|
+
- macOS: `brew install gh`
|
|
63
|
+
- Then: `gh auth login`
|
|
64
|
+
|
|
65
|
+
Without `gh` CLI, this agent cannot function.
|
|
66
|
+
</step>
|
|
67
|
+
|
|
68
|
+
<step name="detect_config" priority="first">
|
|
69
|
+
## Step 0.5: Detect PR Review Directory
|
|
70
|
+
|
|
71
|
+
Locate the pr-review runtime directory. Check in order:
|
|
72
|
+
1. `./__CONFIG_DIR__/pr-review/` (local project install)
|
|
73
|
+
2. `$HOME/__CONFIG_DIR__/pr-review/` (global user install)
|
|
74
|
+
|
|
75
|
+
Store the resolved path as `PR_REVIEW_DIR` for subsequent steps.
|
|
76
|
+
If neither exists, inform user to run the installer: `npx pr-review-agent`
|
|
77
|
+
</step>
|
|
78
|
+
|
|
79
|
+
<step name="load_context" priority="first">
|
|
80
|
+
## Step 1: Load Review Context
|
|
81
|
+
|
|
82
|
+
1. Read CLAUDE.md (or project instructions) for project rules
|
|
83
|
+
2. Read ./REVIEW-PLAN.md for checklist. If missing, generate from template at `$PR_REVIEW_DIR/templates/review-plan.md`
|
|
84
|
+
3. Read any project skills for architectural patterns
|
|
85
|
+
4. Parse the PR URL/number from arguments
|
|
86
|
+
5. Fetch PR metadata:
|
|
87
|
+
```bash
|
|
88
|
+
gh pr view {PR_NUMBER} --repo {OWNER/REPO} --json title,body,headRefName,baseRefName,files,additions,deletions,changedFiles
|
|
89
|
+
```
|
|
90
|
+
6. Fetch existing review comments to avoid duplicates:
|
|
91
|
+
```bash
|
|
92
|
+
gh api repos/{OWNER/REPO}/pulls/{PR_NUMBER}/comments --paginate --jq '.[] | "FILE: \(.path)\nBODY: \(.body)\n---"'
|
|
93
|
+
```
|
|
94
|
+
</step>
|
|
95
|
+
|
|
96
|
+
<step name="analyze_changes">
|
|
97
|
+
## Step 2: Analyze Code Changes
|
|
98
|
+
|
|
99
|
+
For each code file in the PR (skip .planning/, .md, lock files, migrations):
|
|
100
|
+
|
|
101
|
+
1. Fetch the diff:
|
|
102
|
+
```bash
|
|
103
|
+
gh api repos/{OWNER/REPO}/pulls/{PR_NUMBER}/files --paginate --jq '.[] | select(.filename == "FILE") | .patch'
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
2. Analyze against REVIEW-PLAN.md checklist categories.
|
|
107
|
+
|
|
108
|
+
3. For each finding, record:
|
|
109
|
+
- file path, category, severity (critical/warning/suggestion)
|
|
110
|
+
- title (short, descriptive), body (detailed explanation with code examples)
|
|
111
|
+
- line number (approximate)
|
|
112
|
+
|
|
113
|
+
**Deduplication rules:**
|
|
114
|
+
- If the same pattern violation appears in 5+ files, consolidate into one finding referencing all files
|
|
115
|
+
- If an existing comment already covers a finding, skip it
|
|
116
|
+
</step>
|
|
117
|
+
|
|
118
|
+
<step name="generate_output">
|
|
119
|
+
## Step 3: Generate Review Output
|
|
120
|
+
|
|
121
|
+
### 3a. Write findings JSON
|
|
122
|
+
Write the findings array to `$PR_REVIEW_DIR/findings.json`
|
|
123
|
+
|
|
124
|
+
### 3b. Update config.json
|
|
125
|
+
Write/update `$PR_REVIEW_DIR/config.json` with PR metadata and category definitions.
|
|
126
|
+
|
|
127
|
+
The HTML template (`$PR_REVIEW_DIR/index.html`) loads data dynamically from these JSON files via `fetch()`.
|
|
128
|
+
|
|
129
|
+
### 3c. Summary report
|
|
130
|
+
Print a summary table with counts by category and severity.
|
|
131
|
+
</step>
|
|
132
|
+
|
|
133
|
+
<step name="post_comments">
|
|
134
|
+
## Step 4: Post Comments (Optional)
|
|
135
|
+
|
|
136
|
+
Only if the user requests it (`--post` flag). Consolidate findings per file to reduce noise.
|
|
137
|
+
</step>
|
|
138
|
+
|
|
139
|
+
</execution_flow>
|
|
140
|
+
|
|
141
|
+
<success_criteria>
|
|
142
|
+
- [ ] All code files in PR analyzed against REVIEW-PLAN.md checklist
|
|
143
|
+
- [ ] No duplicate findings (checked against existing comments)
|
|
144
|
+
- [ ] findings.json written with structured data
|
|
145
|
+
- [ ] config.json written with PR metadata
|
|
146
|
+
- [ ] Summary printed to user
|
|
147
|
+
- [ ] User prompted about posting comments
|
|
148
|
+
</success_criteria>
|
package/bin/install.js
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* pr-review-agent installer
|
|
4
|
+
* Usage: npx pr-review-agent@latest
|
|
5
|
+
*
|
|
6
|
+
* Installs the PR review agent (commands, agents, template files)
|
|
7
|
+
* into your AI coding assistant's config directory.
|
|
8
|
+
*
|
|
9
|
+
* Supports: Claude Code, OpenCode (more coming)
|
|
10
|
+
* Scope: Global (user-wide) or Local (project-only)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const readline = require('readline');
|
|
16
|
+
const os = require('os');
|
|
17
|
+
|
|
18
|
+
const VERSION = require('../package.json').version;
|
|
19
|
+
const PKG_ROOT = path.resolve(__dirname, '..');
|
|
20
|
+
|
|
21
|
+
// ===== Runtime definitions =====
|
|
22
|
+
const RUNTIMES = {
|
|
23
|
+
claude: {
|
|
24
|
+
name: 'Claude Code',
|
|
25
|
+
configDirName: '.claude',
|
|
26
|
+
globalDir: () => path.join(process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude')),
|
|
27
|
+
localDir: () => path.join(process.cwd(), '.claude'),
|
|
28
|
+
commandsDir: 'commands/pr-review',
|
|
29
|
+
agentsDir: 'agents',
|
|
30
|
+
},
|
|
31
|
+
opencode: {
|
|
32
|
+
name: 'OpenCode',
|
|
33
|
+
configDirName: '.config/opencode',
|
|
34
|
+
globalDir: () => path.join(os.homedir(), '.config', 'opencode'),
|
|
35
|
+
localDir: () => path.join(process.cwd(), '.config', 'opencode'),
|
|
36
|
+
commandsDir: 'commands/pr-review',
|
|
37
|
+
agentsDir: 'agents',
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// ===== ANSI colors =====
|
|
42
|
+
const c = {
|
|
43
|
+
reset: '\x1b[0m',
|
|
44
|
+
bold: '\x1b[1m',
|
|
45
|
+
dim: '\x1b[2m',
|
|
46
|
+
purple: '\x1b[35m',
|
|
47
|
+
green: '\x1b[32m',
|
|
48
|
+
yellow: '\x1b[33m',
|
|
49
|
+
red: '\x1b[31m',
|
|
50
|
+
cyan: '\x1b[36m',
|
|
51
|
+
blue: '\x1b[34m',
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// ===== CLI arg parsing =====
|
|
55
|
+
const args = process.argv.slice(2);
|
|
56
|
+
const flags = new Set(args.filter(a => a.startsWith('--')).map(a => a.slice(2)));
|
|
57
|
+
|
|
58
|
+
function hasFlag(name) { return flags.has(name); }
|
|
59
|
+
|
|
60
|
+
// ===== Helpers =====
|
|
61
|
+
function log(msg = '') { process.stdout.write(msg + '\n'); }
|
|
62
|
+
|
|
63
|
+
function banner() {
|
|
64
|
+
log('');
|
|
65
|
+
log(` ${c.purple}${c.bold}╔═══════════════════════════════════════╗${c.reset}`);
|
|
66
|
+
log(` ${c.purple}${c.bold}║ PR Review Agent v${VERSION.padEnd(12)}║${c.reset}`);
|
|
67
|
+
log(` ${c.purple}${c.bold}╚═══════════════════════════════════════╝${c.reset}`);
|
|
68
|
+
log('');
|
|
69
|
+
log(` ${c.dim}AI-powered PR review for Claude Code & more${c.reset}`);
|
|
70
|
+
log('');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function prompt(question) {
|
|
74
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
75
|
+
return new Promise(resolve => {
|
|
76
|
+
rl.question(` ${question}`, answer => { rl.close(); resolve(answer.trim()); });
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function mkdirp(dir) {
|
|
81
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// configDirName is set during install (e.g. '.claude', '.config/opencode')
|
|
85
|
+
let configDirName = '.claude';
|
|
86
|
+
|
|
87
|
+
function copyFile(src, dest) {
|
|
88
|
+
mkdirp(path.dirname(dest));
|
|
89
|
+
// Rewrite __CONFIG_DIR__ placeholder in text files (.md, .js)
|
|
90
|
+
const ext = path.extname(src);
|
|
91
|
+
if (['.md', '.js', '.json'].includes(ext)) {
|
|
92
|
+
let content = fs.readFileSync(src, 'utf-8');
|
|
93
|
+
content = content.replace(/__CONFIG_DIR__/g, configDirName);
|
|
94
|
+
fs.writeFileSync(dest, content, 'utf-8');
|
|
95
|
+
} else {
|
|
96
|
+
fs.copyFileSync(src, dest);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function copyDir(src, dest) {
|
|
101
|
+
mkdirp(dest);
|
|
102
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
103
|
+
const srcPath = path.join(src, entry.name);
|
|
104
|
+
const destPath = path.join(dest, entry.name);
|
|
105
|
+
if (entry.isDirectory()) copyDir(srcPath, destPath);
|
|
106
|
+
else copyFile(srcPath, destPath);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ===== Uninstall =====
|
|
111
|
+
function uninstall(configDir) {
|
|
112
|
+
const toRemove = [
|
|
113
|
+
path.join(configDir, 'commands', 'pr-review'),
|
|
114
|
+
path.join(configDir, 'agents', 'pr-reviewer.md'),
|
|
115
|
+
path.join(configDir, 'pr-review'),
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
let removed = 0;
|
|
119
|
+
for (const p of toRemove) {
|
|
120
|
+
if (fs.existsSync(p)) {
|
|
121
|
+
const stat = fs.statSync(p);
|
|
122
|
+
if (stat.isDirectory()) fs.rmSync(p, { recursive: true });
|
|
123
|
+
else fs.unlinkSync(p);
|
|
124
|
+
removed++;
|
|
125
|
+
log(` ${c.red}removed${c.reset} ${p}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (removed === 0) log(` ${c.yellow}Nothing to uninstall.${c.reset}`);
|
|
130
|
+
else log(`\n ${c.green}Uninstalled PR Review Agent.${c.reset}`);
|
|
131
|
+
log('');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ===== Install =====
|
|
135
|
+
function install(runtime, configDir) {
|
|
136
|
+
const rt = RUNTIMES[runtime];
|
|
137
|
+
// Set configDirName for path rewriting in copyFile
|
|
138
|
+
configDirName = rt.configDirName;
|
|
139
|
+
// Template goes inside configDir as pr-review/ (like GSD uses get-shit-done/)
|
|
140
|
+
const templateDest = path.join(configDir, 'pr-review');
|
|
141
|
+
|
|
142
|
+
log(` ${c.cyan}Installing for ${rt.name}...${c.reset}`);
|
|
143
|
+
log('');
|
|
144
|
+
|
|
145
|
+
// 1. Copy commands
|
|
146
|
+
const cmdSrc = path.join(PKG_ROOT, 'commands', 'pr-review');
|
|
147
|
+
const cmdDest = path.join(configDir, rt.commandsDir);
|
|
148
|
+
copyDir(cmdSrc, cmdDest);
|
|
149
|
+
const cmdCount = fs.readdirSync(cmdSrc).length;
|
|
150
|
+
log(` ${c.green}+${c.reset} ${cmdCount} commands ${c.dim}→ ${cmdDest}${c.reset}`);
|
|
151
|
+
|
|
152
|
+
// 2. Copy agent
|
|
153
|
+
const agentSrc = path.join(PKG_ROOT, 'agents', 'pr-reviewer.md');
|
|
154
|
+
const agentDest = path.join(configDir, rt.agentsDir, 'pr-reviewer.md');
|
|
155
|
+
copyFile(agentSrc, agentDest);
|
|
156
|
+
log(` ${c.green}+${c.reset} 1 agent ${c.dim}→ ${agentDest}${c.reset}`);
|
|
157
|
+
|
|
158
|
+
// 3. Copy runtime files (index.html, serve.js, templates/)
|
|
159
|
+
const runtimeFiles = ['index.html', 'serve.js', '.gitignore'];
|
|
160
|
+
mkdirp(templateDest);
|
|
161
|
+
for (const f of runtimeFiles) {
|
|
162
|
+
const src = path.join(PKG_ROOT, 'template', f);
|
|
163
|
+
if (fs.existsSync(src)) copyFile(src, path.join(templateDest, f));
|
|
164
|
+
}
|
|
165
|
+
// Copy review-plan template (used by /pr-review:setup to generate REVIEW-PLAN.md)
|
|
166
|
+
const tplSrc = path.join(PKG_ROOT, 'template', 'templates');
|
|
167
|
+
const tplDest = path.join(templateDest, 'templates');
|
|
168
|
+
if (fs.existsSync(tplSrc)) copyDir(tplSrc, tplDest);
|
|
169
|
+
log(` ${c.green}+${c.reset} runtime ${c.dim}→ ${templateDest}${c.reset}`);
|
|
170
|
+
|
|
171
|
+
// 4. Write version file
|
|
172
|
+
fs.writeFileSync(path.join(templateDest, '.version'), VERSION);
|
|
173
|
+
|
|
174
|
+
// 5. Ensure .gitignore in template dir
|
|
175
|
+
const gitignorePath = path.join(templateDest, '.gitignore');
|
|
176
|
+
if (!fs.existsSync(gitignorePath)) {
|
|
177
|
+
fs.writeFileSync(gitignorePath, '# Generated on each review run\nfindings.json\nconfig.json\n');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
log('');
|
|
181
|
+
log(` ${c.green}${c.bold}PR Review Agent v${VERSION} installed!${c.reset}`);
|
|
182
|
+
log('');
|
|
183
|
+
log(` ${c.bold}Quick start:${c.reset}`);
|
|
184
|
+
log(` ${c.dim}1.${c.reset} Generate your review plan (first time only):`);
|
|
185
|
+
log(` ${c.cyan}/pr-review:setup${c.reset}`);
|
|
186
|
+
log(` ${c.dim}2.${c.reset} Review a PR:`);
|
|
187
|
+
log(` ${c.cyan}/pr-review:review <pr-url>${c.reset}`);
|
|
188
|
+
log(` ${c.dim}3.${c.reset} Preview findings in browser:`);
|
|
189
|
+
log(` ${c.cyan}node ${rt.configDirName}/pr-review/serve.js${c.reset}`);
|
|
190
|
+
log('');
|
|
191
|
+
log(` ${c.dim}Commands:${c.reset}`);
|
|
192
|
+
log(` /pr-review:setup ${c.dim}— Generate REVIEW-PLAN.md for your project${c.reset}`);
|
|
193
|
+
log(` /pr-review:review ${c.dim}— Analyze a PR against your review plan${c.reset}`);
|
|
194
|
+
log('');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ===== Main =====
|
|
198
|
+
async function main() {
|
|
199
|
+
const isTTY = process.stdin.isTTY && process.stdout.isTTY;
|
|
200
|
+
|
|
201
|
+
// Non-interactive defaults
|
|
202
|
+
if (!isTTY || hasFlag('help')) {
|
|
203
|
+
if (hasFlag('help')) {
|
|
204
|
+
banner();
|
|
205
|
+
log(` ${c.bold}Usage:${c.reset} npx pr-review-agent@latest [options]`);
|
|
206
|
+
log('');
|
|
207
|
+
log(` ${c.bold}Options:${c.reset}`);
|
|
208
|
+
log(` --claude Install for Claude Code`);
|
|
209
|
+
log(` --opencode Install for OpenCode`);
|
|
210
|
+
log(` --global Install user-wide (default)`);
|
|
211
|
+
log(` --local Install in current project only`);
|
|
212
|
+
log(` --uninstall Remove the agent`);
|
|
213
|
+
log(` --help Show this help`);
|
|
214
|
+
log('');
|
|
215
|
+
log(` ${c.bold}Examples:${c.reset}`);
|
|
216
|
+
log(` npx pr-review-agent ${c.dim}# interactive${c.reset}`);
|
|
217
|
+
log(` npx pr-review-agent --claude --local ${c.dim}# Claude, project-level${c.reset}`);
|
|
218
|
+
log(` npx pr-review-agent --claude --global --uninstall`);
|
|
219
|
+
log('');
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
// Non-TTY or has specific flags: resolve from args
|
|
223
|
+
const rt = ['claude', 'opencode'].find(r => hasFlag(r)) || 'claude';
|
|
224
|
+
const scope = hasFlag('local') ? 'local' : 'global';
|
|
225
|
+
const dir = scope === 'local' ? RUNTIMES[rt].localDir() : RUNTIMES[rt].globalDir();
|
|
226
|
+
if (hasFlag('uninstall')) return uninstall(dir);
|
|
227
|
+
return install(rt, dir);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
banner();
|
|
231
|
+
|
|
232
|
+
// Detect flags for non-interactive mode
|
|
233
|
+
const runtimeFlag = ['claude', 'opencode'].find(r => hasFlag(r));
|
|
234
|
+
const scopeFlag = hasFlag('local') ? 'local' : hasFlag('global') ? 'global' : null;
|
|
235
|
+
|
|
236
|
+
// 1. Select runtime
|
|
237
|
+
let runtime = runtimeFlag;
|
|
238
|
+
if (!runtime) {
|
|
239
|
+
log(` ${c.bold}Select your AI coding assistant:${c.reset}`);
|
|
240
|
+
log('');
|
|
241
|
+
log(` ${c.cyan}1${c.reset}) Claude Code`);
|
|
242
|
+
log(` ${c.cyan}2${c.reset}) OpenCode`);
|
|
243
|
+
log('');
|
|
244
|
+
const choice = await prompt(`${c.bold}Enter choice [1]:${c.reset} `);
|
|
245
|
+
runtime = choice === '2' ? 'opencode' : 'claude';
|
|
246
|
+
log('');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// 2. Select scope
|
|
250
|
+
let scope = scopeFlag;
|
|
251
|
+
if (!scope) {
|
|
252
|
+
log(` ${c.bold}Install scope:${c.reset}`);
|
|
253
|
+
log('');
|
|
254
|
+
log(` ${c.cyan}1${c.reset}) Global ${c.dim}— available in all projects (${RUNTIMES[runtime].globalDir()})${c.reset}`);
|
|
255
|
+
log(` ${c.cyan}2${c.reset}) Local ${c.dim}— this project only (${RUNTIMES[runtime].localDir()})${c.reset}`);
|
|
256
|
+
log('');
|
|
257
|
+
const choice = await prompt(`${c.bold}Enter choice [1]:${c.reset} `);
|
|
258
|
+
scope = choice === '2' ? 'local' : 'global';
|
|
259
|
+
log('');
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const configDir = scope === 'local'
|
|
263
|
+
? RUNTIMES[runtime].localDir()
|
|
264
|
+
: RUNTIMES[runtime].globalDir();
|
|
265
|
+
|
|
266
|
+
// 3. Uninstall or install
|
|
267
|
+
if (hasFlag('uninstall')) {
|
|
268
|
+
uninstall(configDir);
|
|
269
|
+
} else {
|
|
270
|
+
install(runtime, configDir);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
main().catch(err => {
|
|
275
|
+
log(`\n ${c.red}${c.bold}Error:${c.reset} ${err.message}`);
|
|
276
|
+
process.exit(1);
|
|
277
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pr-review:review
|
|
3
|
+
description: Analyze a GitHub PR against project architectural patterns and generate an interactive review preview. Posts comments to GitHub optionally.
|
|
4
|
+
argument-hint: "<pr-url-or-number> [--post] [--focus security|i18n|architecture|design-tokens|all]"
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Write
|
|
8
|
+
- Bash
|
|
9
|
+
- Glob
|
|
10
|
+
- Grep
|
|
11
|
+
- AskUserQuestion
|
|
12
|
+
agent: pr-reviewer
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<objective>
|
|
16
|
+
Perform a comprehensive code review on a GitHub pull request by analyzing diffs against
|
|
17
|
+
project-specific conventions defined in project instructions, skills, and ./REVIEW-PLAN.md.
|
|
18
|
+
Generates structured findings and optionally posts comments to the PR.
|
|
19
|
+
</objective>
|
|
20
|
+
|
|
21
|
+
<execution_context>
|
|
22
|
+
@./REVIEW-PLAN.md
|
|
23
|
+
@./CLAUDE.md
|
|
24
|
+
</execution_context>
|
|
25
|
+
|
|
26
|
+
<context>
|
|
27
|
+
PR identifier: $ARGUMENTS (GitHub URL, org/repo#N, or PR number)
|
|
28
|
+
|
|
29
|
+
**Flags:**
|
|
30
|
+
- `--post` — Post findings as comments on the GitHub PR
|
|
31
|
+
- `--focus security` — Focus on security patterns only
|
|
32
|
+
- `--focus i18n` — Focus on i18n violations only
|
|
33
|
+
- `--focus architecture` — Focus on architectural patterns only
|
|
34
|
+
- `--focus design-tokens` — Focus on design token violations only
|
|
35
|
+
- `--focus all` — Full review (default)
|
|
36
|
+
|
|
37
|
+
**Prerequisites:**
|
|
38
|
+
- GitHub CLI (`gh`) installed and authenticated
|
|
39
|
+
- `./REVIEW-PLAN.md` exists (run `/pr-review:setup` to generate it)
|
|
40
|
+
|
|
41
|
+
**First run:** If `REVIEW-PLAN.md` doesn't exist, generate it from the template at
|
|
42
|
+
`__CONFIG_DIR__/pr-review/templates/review-plan.md` — copy to `./REVIEW-PLAN.md` and ask the
|
|
43
|
+
user to customize the "Project-Specific Rules" section before proceeding.
|
|
44
|
+
</context>
|
|
45
|
+
|
|
46
|
+
<process>
|
|
47
|
+
1. Verify gh CLI is available and authenticated
|
|
48
|
+
2. Detect pr-review directory (local `__CONFIG_DIR__/pr-review/` or global `$HOME/__CONFIG_DIR__/pr-review/`)
|
|
49
|
+
3. If REVIEW-PLAN.md doesn't exist at project root, generate it from template and notify user
|
|
50
|
+
4. Load project context (project instructions, skills, REVIEW-PLAN.md)
|
|
51
|
+
5. Fetch PR metadata and existing comments
|
|
52
|
+
6. Analyze each code file against review checklist
|
|
53
|
+
7. Generate structured findings (`$PR_REVIEW_DIR/findings.json`)
|
|
54
|
+
8. Generate config (`$PR_REVIEW_DIR/config.json`)
|
|
55
|
+
9. Print summary to user
|
|
56
|
+
10. If --post flag: ask confirmation then post comments to PR
|
|
57
|
+
</process>
|
|
58
|
+
|
|
59
|
+
<success_criteria>
|
|
60
|
+
- [ ] All code files analyzed against project patterns
|
|
61
|
+
- [ ] findings.json created
|
|
62
|
+
- [ ] config.json created
|
|
63
|
+
- [ ] Summary table displayed
|
|
64
|
+
- [ ] Comments posted to PR (if --post flag used)
|
|
65
|
+
</success_criteria>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pr-review:setup
|
|
3
|
+
description: Initialize PR review for the current project. Generates REVIEW-PLAN.md with project-specific criteria.
|
|
4
|
+
argument-hint: ""
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Write
|
|
8
|
+
- Bash
|
|
9
|
+
- Glob
|
|
10
|
+
- AskUserQuestion
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<objective>
|
|
14
|
+
Set up PR review for the current project. Generates a REVIEW-PLAN.md at the project
|
|
15
|
+
root with review criteria tailored to the project's stack and patterns.
|
|
16
|
+
|
|
17
|
+
This is similar to how `/gsd:new-project` generates PROJECT.md — the review plan
|
|
18
|
+
is a project-level file that developers edit and commit, not agent infrastructure.
|
|
19
|
+
</objective>
|
|
20
|
+
|
|
21
|
+
<context>
|
|
22
|
+
$ARGUMENTS
|
|
23
|
+
|
|
24
|
+
**What gets created:**
|
|
25
|
+
- `./REVIEW-PLAN.md` — Review criteria checklist at project root (developer-editable, committed to repo)
|
|
26
|
+
|
|
27
|
+
**What already exists (installed by the agent):**
|
|
28
|
+
- `__CONFIG_DIR__/pr-review/index.html` — Interactive preview UI
|
|
29
|
+
- `__CONFIG_DIR__/pr-review/serve.js` — Local dev server for the preview
|
|
30
|
+
- `__CONFIG_DIR__/pr-review/templates/review-plan.md` — Base template
|
|
31
|
+
</context>
|
|
32
|
+
|
|
33
|
+
<process>
|
|
34
|
+
|
|
35
|
+
## Step 1: Check Prerequisites
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
gh --version 2>/dev/null || echo "gh not installed"
|
|
39
|
+
gh auth status 2>/dev/null || echo "gh not authenticated"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
If `gh` is not available, ask the user:
|
|
43
|
+
- "GitHub CLI is required for PR review. Would you like to install it?"
|
|
44
|
+
- Windows: `winget install GitHub.cli --source winget`
|
|
45
|
+
- macOS: `brew install gh`
|
|
46
|
+
- Then: `gh auth login`
|
|
47
|
+
|
|
48
|
+
## Step 2: Detect PR Review Directory
|
|
49
|
+
|
|
50
|
+
Locate the pr-review runtime:
|
|
51
|
+
1. `./__CONFIG_DIR__/pr-review/` (local)
|
|
52
|
+
2. `$HOME/__CONFIG_DIR__/pr-review/` (global)
|
|
53
|
+
|
|
54
|
+
If neither exists, inform user to install: `npx pr-review-agent`
|
|
55
|
+
|
|
56
|
+
## Step 3: Discover Project Context
|
|
57
|
+
|
|
58
|
+
Read these files to understand the project:
|
|
59
|
+
- `./CLAUDE.md` or equivalent project instructions
|
|
60
|
+
- Project skills directory (if any)
|
|
61
|
+
- `package.json` or equivalent — detect stack
|
|
62
|
+
|
|
63
|
+
## Step 4: Generate REVIEW-PLAN.md
|
|
64
|
+
|
|
65
|
+
1. Read the base template from `$PR_REVIEW_DIR/templates/review-plan.md`
|
|
66
|
+
2. Ask the user about their project:
|
|
67
|
+
- Backend framework and patterns to enforce
|
|
68
|
+
- Frontend framework and patterns to enforce
|
|
69
|
+
- Key rules they want every PR checked against
|
|
70
|
+
- Any additional custom criteria
|
|
71
|
+
3. Generate `./REVIEW-PLAN.md` at the project root, customizing the template
|
|
72
|
+
with the project's specific stack, patterns, and rules
|
|
73
|
+
4. If project instructions or skills define architectural patterns, incorporate those
|
|
74
|
+
automatically into the "Project-Specific Rules" section
|
|
75
|
+
|
|
76
|
+
**Important:** Do NOT hardcode framework-specific rules in the template.
|
|
77
|
+
Generate them dynamically based on what the project actually uses.
|
|
78
|
+
|
|
79
|
+
## Step 5: Confirm
|
|
80
|
+
|
|
81
|
+
Tell the user:
|
|
82
|
+
- Where REVIEW-PLAN.md was created
|
|
83
|
+
- That they can edit it anytime
|
|
84
|
+
- That the agent reads it before every `/pr-review:review` run
|
|
85
|
+
- How to start reviewing: `/pr-review:review <pr-url>`
|
|
86
|
+
|
|
87
|
+
</process>
|
|
88
|
+
|
|
89
|
+
<success_criteria>
|
|
90
|
+
- [ ] gh CLI verified or installation guided
|
|
91
|
+
- [ ] Project stack detected
|
|
92
|
+
- [ ] REVIEW-PLAN.md generated at project root with project-specific criteria
|
|
93
|
+
- [ ] User informed about next steps
|
|
94
|
+
</success_criteria>
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pr-review-agent",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "AI-powered PR review agent for Claude Code, OpenCode, and other AI coding assistants. Analyzes pull requests against project-specific architectural patterns with an interactive preview UI.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"pr-review-agent": "bin/install.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin",
|
|
10
|
+
"commands",
|
|
11
|
+
"agents",
|
|
12
|
+
"template"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"claude-code",
|
|
16
|
+
"code-review",
|
|
17
|
+
"pull-request",
|
|
18
|
+
"ai-agent",
|
|
19
|
+
"opencode",
|
|
20
|
+
"pr-review",
|
|
21
|
+
"linter"
|
|
22
|
+
],
|
|
23
|
+
"author": "TheRocketCodeMX",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18.0.0"
|
|
27
|
+
},
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/TheRocketCodeMX/pr-review-agent"
|
|
31
|
+
}
|
|
32
|
+
}
|