claude-issue-solver 1.22.0 → 1.23.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 +4 -3
- package/dist/commands/review.d.ts +1 -0
- package/dist/commands/review.js +223 -11
- package/dist/index.js +12 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -128,8 +128,9 @@ claude-issue new "Fix crash" -l bug -l priority
|
|
|
128
128
|
# Create PR for a solved issue (if you skipped it earlier)
|
|
129
129
|
claude-issue pr 42
|
|
130
130
|
|
|
131
|
-
# Review
|
|
132
|
-
claude-issue review
|
|
131
|
+
# Review PRs with AI (posts suggestions you can commit on GitHub)
|
|
132
|
+
claude-issue review # Interactive: select PRs to review in parallel
|
|
133
|
+
claude-issue review 42 # Review specific issue's PR
|
|
133
134
|
|
|
134
135
|
# Clean up worktree and branch
|
|
135
136
|
claude-issue clean 42 # Clean specific issue
|
|
@@ -155,7 +156,7 @@ claude-issue --help
|
|
|
155
156
|
| `claude-issue list` | `ls` | List open issues |
|
|
156
157
|
| `claude-issue show <number>` | - | Show full issue details |
|
|
157
158
|
| `claude-issue pr <number>` | - | Create PR for solved issue |
|
|
158
|
-
| `claude-issue review
|
|
159
|
+
| `claude-issue review [number]` | - | Review PRs with AI suggestions |
|
|
159
160
|
| `claude-issue clean [number]` | `rm` | Remove worktree and branch |
|
|
160
161
|
| `claude-issue go [number]` | - | Navigate to worktree |
|
|
161
162
|
| `claude-issue init` | - | Setup wizard for requirements |
|
package/dist/commands/review.js
CHANGED
|
@@ -37,8 +37,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.reviewCommand = reviewCommand;
|
|
40
|
+
exports.selectReviewCommand = selectReviewCommand;
|
|
40
41
|
const chalk_1 = __importDefault(require("chalk"));
|
|
41
42
|
const ora_1 = __importDefault(require("ora"));
|
|
43
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
42
44
|
const fs = __importStar(require("fs"));
|
|
43
45
|
const path = __importStar(require("path"));
|
|
44
46
|
const child_process_1 = require("child_process");
|
|
@@ -165,10 +167,10 @@ Review the code changes in this PR. Look for:
|
|
|
165
167
|
6. Performance problems
|
|
166
168
|
|
|
167
169
|
## How to Leave Feedback
|
|
168
|
-
Use the gh CLI to post
|
|
170
|
+
Use the gh CLI to post comments with suggestions. For each issue you find:
|
|
169
171
|
|
|
170
172
|
\`\`\`bash
|
|
171
|
-
gh pr
|
|
173
|
+
gh pr comment ${prNumber} --body "**File: path/to/file.ts**
|
|
172
174
|
|
|
173
175
|
Description of the issue...
|
|
174
176
|
|
|
@@ -180,21 +182,16 @@ Description of the issue...
|
|
|
180
182
|
|
|
181
183
|
The \`suggestion\` code block will create a "Commit suggestion" button on GitHub.
|
|
182
184
|
|
|
183
|
-
For a final review summary
|
|
185
|
+
For a final review summary:
|
|
184
186
|
\`\`\`bash
|
|
185
|
-
gh pr
|
|
187
|
+
gh pr comment ${prNumber} --body "## Review Summary
|
|
186
188
|
|
|
187
189
|
- Issue 1: ...
|
|
188
190
|
- Issue 2: ...
|
|
189
|
-
|
|
190
|
-
Overall: [APPROVE/REQUEST_CHANGES/COMMENT]"
|
|
191
|
+
"
|
|
191
192
|
\`\`\`
|
|
192
193
|
|
|
193
|
-
|
|
194
|
-
\`\`\`bash
|
|
195
|
-
gh pr review ${prNumber} --approve --body "LGTM! Code looks good."
|
|
196
|
-
gh pr review ${prNumber} --request-changes --body "Please address the issues above."
|
|
197
|
-
\`\`\`
|
|
194
|
+
Note: You cannot approve or request changes on your own PR. Just post suggestions as comments.
|
|
198
195
|
|
|
199
196
|
## PR Diff
|
|
200
197
|
${diffContent ? `\n\`\`\`diff\n${diffContent.slice(0, 50000)}\n\`\`\`\n` : 'Run `gh pr diff ' + prNumber + '` to see the changes.'}
|
|
@@ -262,3 +259,218 @@ function getRepoName(projectRoot) {
|
|
|
262
259
|
return '';
|
|
263
260
|
}
|
|
264
261
|
}
|
|
262
|
+
function getOpenPRs(projectRoot) {
|
|
263
|
+
try {
|
|
264
|
+
const output = (0, child_process_1.execSync)('gh pr list --state open --json number,title,headRefName --limit 50', {
|
|
265
|
+
cwd: projectRoot,
|
|
266
|
+
encoding: 'utf-8',
|
|
267
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
268
|
+
});
|
|
269
|
+
const prs = JSON.parse(output);
|
|
270
|
+
return prs.map((pr) => {
|
|
271
|
+
// Try to extract issue number from branch name (issue-42-slug)
|
|
272
|
+
const match = pr.headRefName.match(/^issue-(\d+)-/);
|
|
273
|
+
return {
|
|
274
|
+
...pr,
|
|
275
|
+
issueNumber: match ? parseInt(match[1], 10) : null,
|
|
276
|
+
};
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
return [];
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
async function selectReviewCommand() {
|
|
284
|
+
const projectRoot = (0, git_1.getProjectRoot)();
|
|
285
|
+
const projectName = (0, git_1.getProjectName)();
|
|
286
|
+
console.log(chalk_1.default.bold(`\nOpen PRs for ${projectName}:\n`));
|
|
287
|
+
const spinner = (0, ora_1.default)('Fetching open PRs...').start();
|
|
288
|
+
const prs = getOpenPRs(projectRoot);
|
|
289
|
+
spinner.stop();
|
|
290
|
+
if (prs.length === 0) {
|
|
291
|
+
console.log(chalk_1.default.yellow('No open PRs found.'));
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
// Build choices for checkbox prompt
|
|
295
|
+
const choices = prs.map((pr) => {
|
|
296
|
+
const issueTag = pr.issueNumber ? chalk_1.default.dim(` (issue #${pr.issueNumber})`) : '';
|
|
297
|
+
return {
|
|
298
|
+
name: `#${pr.number}\t${pr.title}${issueTag}`,
|
|
299
|
+
value: pr,
|
|
300
|
+
checked: false,
|
|
301
|
+
};
|
|
302
|
+
});
|
|
303
|
+
const { selected } = await inquirer_1.default.prompt([
|
|
304
|
+
{
|
|
305
|
+
type: 'checkbox',
|
|
306
|
+
name: 'selected',
|
|
307
|
+
message: 'Select PRs to review (space to toggle, enter to confirm):',
|
|
308
|
+
choices,
|
|
309
|
+
},
|
|
310
|
+
]);
|
|
311
|
+
if (selected.length === 0) {
|
|
312
|
+
console.log(chalk_1.default.dim('No PRs selected.'));
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
console.log();
|
|
316
|
+
console.log(chalk_1.default.cyan(`🔍 Starting ${selected.length} review session(s) in parallel...`));
|
|
317
|
+
console.log();
|
|
318
|
+
// Launch reviews in parallel
|
|
319
|
+
for (const pr of selected) {
|
|
320
|
+
await launchReviewForPR(pr, projectRoot, projectName);
|
|
321
|
+
}
|
|
322
|
+
console.log();
|
|
323
|
+
console.log(chalk_1.default.green(`✅ Started ${selected.length} review session(s)!`));
|
|
324
|
+
console.log(chalk_1.default.dim(' Each review is running in its own terminal window.'));
|
|
325
|
+
}
|
|
326
|
+
async function launchReviewForPR(pr, projectRoot, projectName) {
|
|
327
|
+
const baseBranch = (0, git_1.getDefaultBranch)();
|
|
328
|
+
const branchName = pr.headRefName;
|
|
329
|
+
const worktreePath = path.join(path.dirname(projectRoot), `${projectName}-${branchName}`);
|
|
330
|
+
// Fetch latest
|
|
331
|
+
try {
|
|
332
|
+
(0, child_process_1.execSync)(`git fetch origin ${branchName} --quiet`, { cwd: projectRoot, stdio: 'pipe' });
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
// Ignore fetch errors
|
|
336
|
+
}
|
|
337
|
+
// Check if worktree already exists
|
|
338
|
+
if (!fs.existsSync(worktreePath)) {
|
|
339
|
+
try {
|
|
340
|
+
if ((0, git_1.branchExists)(branchName)) {
|
|
341
|
+
(0, child_process_1.execSync)(`git worktree add "${worktreePath}" "${branchName}"`, {
|
|
342
|
+
cwd: projectRoot,
|
|
343
|
+
stdio: 'pipe',
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
(0, child_process_1.execSync)(`git worktree add "${worktreePath}" "origin/${branchName}"`, {
|
|
348
|
+
cwd: projectRoot,
|
|
349
|
+
stdio: 'pipe',
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
// Copy env files and symlink node_modules
|
|
353
|
+
(0, helpers_1.copyEnvFiles)(projectRoot, worktreePath);
|
|
354
|
+
(0, helpers_1.symlinkNodeModules)(projectRoot, worktreePath);
|
|
355
|
+
}
|
|
356
|
+
catch (error) {
|
|
357
|
+
console.log(chalk_1.default.yellow(`⚠️ Could not create worktree for PR #${pr.number}`));
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
// Pull latest changes
|
|
363
|
+
try {
|
|
364
|
+
(0, child_process_1.execSync)('git pull --quiet', { cwd: worktreePath, stdio: 'pipe' });
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
// Ignore pull errors
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
// Get the diff for context
|
|
371
|
+
let diffContent = '';
|
|
372
|
+
try {
|
|
373
|
+
diffContent = (0, child_process_1.execSync)(`gh pr diff ${pr.number}`, {
|
|
374
|
+
cwd: projectRoot,
|
|
375
|
+
encoding: 'utf-8',
|
|
376
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
377
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
catch {
|
|
381
|
+
// Ignore diff errors
|
|
382
|
+
}
|
|
383
|
+
// Get issue body if we have an issue number
|
|
384
|
+
let issueBody = '';
|
|
385
|
+
if (pr.issueNumber) {
|
|
386
|
+
const issue = (0, github_1.getIssue)(pr.issueNumber);
|
|
387
|
+
if (issue) {
|
|
388
|
+
issueBody = issue.body;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
// Build the review prompt
|
|
392
|
+
const prompt = `You are reviewing PR #${pr.number}: ${pr.title}
|
|
393
|
+
${pr.issueNumber ? `\n## Related Issue #${pr.issueNumber}\n${issueBody}\n` : ''}
|
|
394
|
+
## Your Task
|
|
395
|
+
Review the code changes in this PR. Look for:
|
|
396
|
+
1. Bugs and logic errors
|
|
397
|
+
2. Security vulnerabilities
|
|
398
|
+
3. Missing error handling
|
|
399
|
+
4. Code quality issues
|
|
400
|
+
5. Missing tests
|
|
401
|
+
6. Performance problems
|
|
402
|
+
|
|
403
|
+
## How to Leave Feedback
|
|
404
|
+
Use the gh CLI to post comments with suggestions. For each issue you find:
|
|
405
|
+
|
|
406
|
+
\`\`\`bash
|
|
407
|
+
gh pr comment ${pr.number} --body "**File: path/to/file.ts**
|
|
408
|
+
|
|
409
|
+
Description of the issue...
|
|
410
|
+
|
|
411
|
+
\\\`\\\`\\\`suggestion
|
|
412
|
+
// Your suggested fix here
|
|
413
|
+
\\\`\\\`\\\`
|
|
414
|
+
"
|
|
415
|
+
\`\`\`
|
|
416
|
+
|
|
417
|
+
The \`suggestion\` code block will create a "Commit suggestion" button on GitHub.
|
|
418
|
+
|
|
419
|
+
For a final review summary:
|
|
420
|
+
\`\`\`bash
|
|
421
|
+
gh pr comment ${pr.number} --body "## Review Summary
|
|
422
|
+
|
|
423
|
+
- Issue 1: ...
|
|
424
|
+
- Issue 2: ...
|
|
425
|
+
"
|
|
426
|
+
\`\`\`
|
|
427
|
+
|
|
428
|
+
Note: You cannot approve or request changes on your own PR. Just post suggestions as comments.
|
|
429
|
+
|
|
430
|
+
## PR Diff
|
|
431
|
+
${diffContent ? `\n\`\`\`diff\n${diffContent.slice(0, 50000)}\n\`\`\`\n` : 'Run `gh pr diff ' + pr.number + '` to see the changes.'}
|
|
432
|
+
|
|
433
|
+
Start by examining the diff and the changed files, then provide your review.`;
|
|
434
|
+
// Write prompt to a file
|
|
435
|
+
const promptFile = path.join(worktreePath, '.claude-review-prompt.txt');
|
|
436
|
+
fs.writeFileSync(promptFile, prompt);
|
|
437
|
+
// Create runner script for review
|
|
438
|
+
const runnerScript = path.join(worktreePath, '.claude-review-runner.sh');
|
|
439
|
+
const escapedTitle = pr.title.replace(/"/g, '\\"').slice(0, 50);
|
|
440
|
+
const runnerContent = `#!/bin/bash
|
|
441
|
+
cd "${worktreePath}"
|
|
442
|
+
|
|
443
|
+
# Set terminal title
|
|
444
|
+
echo -ne "\\033]0;Review PR #${pr.number}: ${escapedTitle}\\007"
|
|
445
|
+
|
|
446
|
+
echo "🔍 Claude Code Review - PR #${pr.number}"
|
|
447
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
448
|
+
echo ""
|
|
449
|
+
echo "${escapedTitle}"
|
|
450
|
+
echo ""
|
|
451
|
+
echo "Claude will review the PR and post suggestions."
|
|
452
|
+
echo "You can commit suggestions directly on GitHub."
|
|
453
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
454
|
+
echo ""
|
|
455
|
+
|
|
456
|
+
# Run Claude interactively
|
|
457
|
+
claude --dangerously-skip-permissions "$(cat '${promptFile}')"
|
|
458
|
+
|
|
459
|
+
# Clean up prompt file
|
|
460
|
+
rm -f '${promptFile}'
|
|
461
|
+
|
|
462
|
+
echo ""
|
|
463
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
464
|
+
echo "Review session ended."
|
|
465
|
+
echo ""
|
|
466
|
+
echo "View PR: gh pr view ${pr.number} --web"
|
|
467
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
468
|
+
echo ""
|
|
469
|
+
|
|
470
|
+
# Keep terminal open
|
|
471
|
+
exec bash
|
|
472
|
+
`;
|
|
473
|
+
fs.writeFileSync(runnerScript, runnerContent, { mode: 0o755 });
|
|
474
|
+
console.log(chalk_1.default.dim(` Starting review for PR #${pr.number}: ${pr.title.slice(0, 50)}...`));
|
|
475
|
+
(0, helpers_1.openInNewTerminal)(`'${runnerScript}'`);
|
|
476
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -153,14 +153,19 @@ program
|
|
|
153
153
|
});
|
|
154
154
|
// Review command - AI code review for PRs
|
|
155
155
|
program
|
|
156
|
-
.command('review
|
|
157
|
-
.description('Review
|
|
156
|
+
.command('review [issue]')
|
|
157
|
+
.description('Review PRs with Claude and post suggestions')
|
|
158
158
|
.action(async (issue) => {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
159
|
+
if (issue) {
|
|
160
|
+
const issueNumber = parseInt(issue, 10);
|
|
161
|
+
if (isNaN(issueNumber)) {
|
|
162
|
+
console.log(chalk_1.default.red(`❌ Invalid issue number: ${issue}`));
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
await (0, review_1.reviewCommand)(issueNumber);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
await (0, review_1.selectReviewCommand)();
|
|
163
169
|
}
|
|
164
|
-
await (0, review_1.reviewCommand)(issueNumber);
|
|
165
170
|
});
|
|
166
171
|
program.parse();
|