claude-issue-solver 1.32.0 → 1.34.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.
@@ -43,6 +43,7 @@ const ora_1 = __importDefault(require("ora"));
43
43
  const inquirer_1 = __importDefault(require("inquirer"));
44
44
  const fs = __importStar(require("fs"));
45
45
  const path = __importStar(require("path"));
46
+ const os = __importStar(require("os"));
46
47
  const child_process_1 = require("child_process");
47
48
  const github_1 = require("../utils/github");
48
49
  const git_1 = require("../utils/git");
@@ -57,22 +58,21 @@ async function reviewCommand(issueNumber, options = {}) {
57
58
  }
58
59
  spinner.succeed(`Found issue #${issueNumber}`);
59
60
  const projectRoot = (0, git_1.getProjectRoot)();
60
- const projectName = (0, git_1.getProjectName)();
61
- const baseBranch = (0, git_1.getDefaultBranch)();
62
- const branchSlug = (0, helpers_1.slugify)(issue.title);
63
- const branchName = `issue-${issueNumber}-${branchSlug}`;
64
- const worktreePath = path.join(path.dirname(projectRoot), `${projectName}-${branchName}`);
65
- // Check if there's a PR for this issue
61
+ // Check if there's a PR for this issue - search by issue number in all PRs
66
62
  const prCheckSpinner = (0, ora_1.default)('Checking for PR...').start();
67
63
  let prNumber = null;
64
+ let branchName = null;
68
65
  try {
69
- const prOutput = (0, child_process_1.execSync)(`gh pr list --head "${branchName}" --json number --jq '.[0].number'`, {
66
+ // Search for PRs that mention the issue number in their branch name
67
+ const prOutput = (0, child_process_1.execSync)(`gh pr list --state open --json number,headRefName --jq '.[] | select(.headRefName | test("issue-${issueNumber}-")) | "\\(.number) \\(.headRefName)"'`, {
70
68
  cwd: projectRoot,
71
69
  encoding: 'utf-8',
72
70
  stdio: ['pipe', 'pipe', 'pipe'],
73
71
  }).trim();
74
72
  if (prOutput) {
75
- prNumber = prOutput;
73
+ const [num, branch] = prOutput.split(' ');
74
+ prNumber = num;
75
+ branchName = branch;
76
76
  prCheckSpinner.succeed(`Found PR #${prNumber}`);
77
77
  }
78
78
  else {
@@ -90,55 +90,6 @@ async function reviewCommand(issueNumber, options = {}) {
90
90
  console.log(chalk_1.default.bold(`šŸ“Œ Reviewing: ${issue.title}`));
91
91
  console.log(chalk_1.default.dim(`šŸ”— PR: https://github.com/${getRepoName(projectRoot)}/pull/${prNumber}`));
92
92
  console.log();
93
- // Fetch latest
94
- const fetchSpinner = (0, ora_1.default)(`Fetching latest changes...`).start();
95
- try {
96
- (0, child_process_1.execSync)(`git fetch origin ${branchName} --quiet`, { cwd: projectRoot, stdio: 'pipe' });
97
- fetchSpinner.succeed('Fetched latest changes');
98
- }
99
- catch {
100
- fetchSpinner.warn('Could not fetch branch');
101
- }
102
- // Check if worktree already exists
103
- if (fs.existsSync(worktreePath)) {
104
- console.log(chalk_1.default.yellow(`\n🌿 Using existing worktree at: ${worktreePath}`));
105
- // Pull latest changes
106
- try {
107
- (0, child_process_1.execSync)('git pull --quiet', { cwd: worktreePath, stdio: 'pipe' });
108
- }
109
- catch {
110
- // Ignore pull errors
111
- }
112
- }
113
- else {
114
- const worktreeSpinner = (0, ora_1.default)(`Creating worktree for review...`).start();
115
- try {
116
- if ((0, git_1.branchExists)(branchName)) {
117
- (0, child_process_1.execSync)(`git worktree add "${worktreePath}" "${branchName}"`, {
118
- cwd: projectRoot,
119
- stdio: 'pipe',
120
- });
121
- }
122
- else {
123
- // Branch should exist if PR exists, but handle edge case
124
- (0, child_process_1.execSync)(`git worktree add "${worktreePath}" "origin/${branchName}"`, {
125
- cwd: projectRoot,
126
- stdio: 'pipe',
127
- });
128
- }
129
- worktreeSpinner.succeed(`Created worktree at: ${worktreePath}`);
130
- }
131
- catch (error) {
132
- worktreeSpinner.fail('Failed to create worktree');
133
- console.error(error);
134
- process.exit(1);
135
- }
136
- // Copy env files and symlink node_modules
137
- const setupSpinner = (0, ora_1.default)('Setting up worktree...').start();
138
- (0, helpers_1.copyEnvFiles)(projectRoot, worktreePath);
139
- (0, helpers_1.symlinkNodeModules)(projectRoot, worktreePath);
140
- setupSpinner.succeed('Worktree setup complete');
141
- }
142
93
  // Get the diff for context
143
94
  let diffContent = '';
144
95
  try {
@@ -247,8 +198,9 @@ The \`suggestion\` code block creates a "Commit suggestion" button on GitHub.
247
198
  ${diffContent ? `\n\`\`\`diff\n${diffContent.slice(0, 50000)}\n\`\`\`\n` : 'Run `gh pr diff ' + prNumber + '` to see the changes.'}
248
199
 
249
200
  Start by examining the diff and the changed files, then provide your review.`;
250
- // Write prompt to a file
251
- const promptFile = path.join(worktreePath, '.claude-review-prompt.txt');
201
+ // Write prompt and runner script to temp directory
202
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cis-review-'));
203
+ const promptFile = path.join(tempDir, '.claude-review-prompt.txt');
252
204
  fs.writeFileSync(promptFile, prompt);
253
205
  // Bot token already fetched above
254
206
  const botTokenEnv = botToken ? `export BOT_TOKEN="${botToken}"\nexport GH_TOKEN="${botToken}"` : '# No bot token configured';
@@ -256,9 +208,9 @@ Start by examining the diff and the changed files, then provide your review.`;
256
208
  ? 'Using bot token for reviews (can approve/request changes)'
257
209
  : 'No bot token - using your account (may have limitations on own PRs)';
258
210
  // Create runner script for review
259
- const runnerScript = path.join(worktreePath, '.claude-review-runner.sh');
211
+ const runnerScript = path.join(tempDir, '.claude-review-runner.sh');
260
212
  const runnerContent = `#!/bin/bash
261
- cd "${worktreePath}"
213
+ cd "${projectRoot}"
262
214
 
263
215
  # Set bot token if configured
264
216
  ${botTokenEnv}
@@ -282,8 +234,8 @@ echo ""
282
234
  # Run Claude interactively
283
235
  claude --dangerously-skip-permissions "$(cat '${promptFile}')"
284
236
 
285
- # Clean up prompt file
286
- rm -f '${promptFile}'
237
+ # Clean up temp files
238
+ rm -rf '${tempDir}'
287
239
 
288
240
  echo ""
289
241
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@@ -300,13 +252,6 @@ ${options.merge ? ` echo "šŸ“¤ Auto-merging PR #${prNumber}..."
300
252
  if gh pr merge ${prNumber} --squash --delete-branch; then
301
253
  echo ""
302
254
  echo "āœ… PR merged successfully!"
303
- echo ""
304
- echo "Cleaning up worktree..."
305
- cd "${projectRoot}"
306
- git worktree remove "${worktreePath}" --force 2>/dev/null || rm -rf "${worktreePath}"
307
- git worktree prune 2>/dev/null
308
- git branch -D "${branchName}" 2>/dev/null
309
- echo "āœ… Cleanup complete!"
310
255
  else
311
256
  echo ""
312
257
  echo "āš ļø Merge failed. You can try manually: gh pr merge ${prNumber} --squash"
@@ -330,7 +275,6 @@ exec bash
330
275
  console.log(chalk_1.default.dim(` Claude is reviewing in a new terminal window.`));
331
276
  console.log();
332
277
  console.log(chalk_1.default.dim(` View PR: gh pr view ${prNumber} --web`));
333
- console.log(chalk_1.default.dim(` To clean up later: claude-issue clean ${issueNumber}`));
334
278
  }
335
279
  function getRepoName(projectRoot) {
336
280
  try {
@@ -424,50 +368,7 @@ async function selectReviewCommand(options = {}) {
424
368
  console.log(chalk_1.default.green(`āœ… Started ${selected.length} review session(s)!`));
425
369
  console.log(chalk_1.default.dim(' Each review is running in its own terminal window.'));
426
370
  }
427
- async function launchReviewForPR(pr, projectRoot, projectName, options = {}) {
428
- const baseBranch = (0, git_1.getDefaultBranch)();
429
- const branchName = pr.headRefName;
430
- const worktreePath = path.join(path.dirname(projectRoot), `${projectName}-${branchName}`);
431
- // Fetch latest
432
- try {
433
- (0, child_process_1.execSync)(`git fetch origin ${branchName} --quiet`, { cwd: projectRoot, stdio: 'pipe' });
434
- }
435
- catch {
436
- // Ignore fetch errors
437
- }
438
- // Check if worktree already exists
439
- if (!fs.existsSync(worktreePath)) {
440
- try {
441
- if ((0, git_1.branchExists)(branchName)) {
442
- (0, child_process_1.execSync)(`git worktree add "${worktreePath}" "${branchName}"`, {
443
- cwd: projectRoot,
444
- stdio: 'pipe',
445
- });
446
- }
447
- else {
448
- (0, child_process_1.execSync)(`git worktree add "${worktreePath}" "origin/${branchName}"`, {
449
- cwd: projectRoot,
450
- stdio: 'pipe',
451
- });
452
- }
453
- // Copy env files and symlink node_modules
454
- (0, helpers_1.copyEnvFiles)(projectRoot, worktreePath);
455
- (0, helpers_1.symlinkNodeModules)(projectRoot, worktreePath);
456
- }
457
- catch (error) {
458
- console.log(chalk_1.default.yellow(`āš ļø Could not create worktree for PR #${pr.number}`));
459
- return;
460
- }
461
- }
462
- else {
463
- // Pull latest changes
464
- try {
465
- (0, child_process_1.execSync)('git pull --quiet', { cwd: worktreePath, stdio: 'pipe' });
466
- }
467
- catch {
468
- // Ignore pull errors
469
- }
470
- }
371
+ async function launchReviewForPR(pr, projectRoot, _projectName, options = {}) {
471
372
  // Get the diff for context
472
373
  let diffContent = '';
473
374
  try {
@@ -580,18 +481,19 @@ The \`suggestion\` code block creates a "Commit suggestion" button on GitHub.
580
481
  ${diffContent ? `\n\`\`\`diff\n${diffContent.slice(0, 50000)}\n\`\`\`\n` : 'Run `gh pr diff ' + pr.number + '` to see the changes.'}
581
482
 
582
483
  Start by examining the diff and the changed files, then provide your review.`;
583
- // Write prompt to a file
584
- const promptFile = path.join(worktreePath, '.claude-review-prompt.txt');
484
+ // Write prompt and runner script to temp directory
485
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cis-review-'));
486
+ const promptFile = path.join(tempDir, '.claude-review-prompt.txt');
585
487
  fs.writeFileSync(promptFile, prompt);
586
488
  const botTokenEnv = botToken ? `export BOT_TOKEN="${botToken}"\nexport GH_TOKEN="${botToken}"` : '# No bot token configured';
587
489
  const botNote = botToken
588
490
  ? 'Using bot token for reviews (can approve/request changes)'
589
491
  : 'No bot token - using your account (may have limitations on own PRs)';
590
492
  // Create runner script for review
591
- const runnerScript = path.join(worktreePath, '.claude-review-runner.sh');
493
+ const runnerScript = path.join(tempDir, '.claude-review-runner.sh');
592
494
  const escapedTitle = pr.title.replace(/"/g, '\\"').slice(0, 50);
593
495
  const runnerContent = `#!/bin/bash
594
- cd "${worktreePath}"
496
+ cd "${projectRoot}"
595
497
 
596
498
  # Set bot token if configured
597
499
  ${botTokenEnv}
@@ -615,8 +517,8 @@ echo ""
615
517
  # Run Claude interactively
616
518
  claude --dangerously-skip-permissions "$(cat '${promptFile}')"
617
519
 
618
- # Clean up prompt file
619
- rm -f '${promptFile}'
520
+ # Clean up temp files
521
+ rm -rf '${tempDir}'
620
522
 
621
523
  echo ""
622
524
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@@ -633,13 +535,6 @@ ${options.merge ? ` echo "šŸ“¤ Auto-merging PR #${pr.number}..."
633
535
  if gh pr merge ${pr.number} --squash --delete-branch; then
634
536
  echo ""
635
537
  echo "āœ… PR merged successfully!"
636
- echo ""
637
- echo "Cleaning up worktree..."
638
- cd "${projectRoot}"
639
- git worktree remove "${worktreePath}" --force 2>/dev/null || rm -rf "${worktreePath}"
640
- git worktree prune 2>/dev/null
641
- git branch -D "${branchName}" 2>/dev/null
642
- echo "āœ… Cleanup complete!"
643
538
  else
644
539
  echo ""
645
540
  echo "āš ļø Merge failed. You can try manually: gh pr merge ${pr.number} --squash"
@@ -118,7 +118,8 @@ Instructions:
118
118
  1. Analyze the issue and understand what needs to be done
119
119
  2. Implement the necessary changes
120
120
  3. Make sure to run tests if applicable
121
- 4. When done, commit your changes with a descriptive message that references the issue`;
121
+ 4. When done, commit your changes with a descriptive message that references the issue
122
+ 5. A PR will be created automatically when you commit - no need to create one manually`;
122
123
  // Write prompt to a file to avoid shell escaping issues with backticks, <>, etc.
123
124
  const promptFile = path.join(worktreePath, '.claude-prompt.txt');
124
125
  fs.writeFileSync(promptFile, prompt);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-issue-solver",
3
- "version": "1.32.0",
3
+ "version": "1.34.0",
4
4
  "description": "Automatically solve GitHub issues using Claude Code",
5
5
  "main": "dist/index.js",
6
6
  "bin": {