claude-issue-solver 1.6.2 → 1.6.4

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.
@@ -45,14 +45,13 @@ const fs = __importStar(require("fs"));
45
45
  const path = __importStar(require("path"));
46
46
  const os = __importStar(require("os"));
47
47
  const child_process_1 = require("child_process");
48
- const github_1 = require("../utils/github");
49
48
  const git_1 = require("../utils/git");
50
- const helpers_1 = require("../utils/helpers");
51
- function closeWindowsWithPath(folderPath) {
49
+ function closeWindowsWithPath(folderPath, issueNumber) {
52
50
  if (os.platform() !== 'darwin')
53
51
  return;
54
52
  const folderName = path.basename(folderPath);
55
- // Try to close iTerm2 tabs/windows with this path
53
+ const issuePattern = `Issue #${issueNumber}`;
54
+ // Try to close iTerm2 tabs/windows with this path or issue number
56
55
  try {
57
56
  (0, child_process_1.execSync)(`osascript -e '
58
57
  tell application "iTerm"
@@ -60,7 +59,7 @@ function closeWindowsWithPath(folderPath) {
60
59
  repeat with t in tabs of w
61
60
  repeat with s in sessions of t
62
61
  set sessionName to name of s
63
- if sessionName contains "${folderName}" then
62
+ if sessionName contains "${folderName}" or sessionName contains "${issuePattern}" then
64
63
  close s
65
64
  end if
66
65
  end repeat
@@ -72,12 +71,13 @@ function closeWindowsWithPath(folderPath) {
72
71
  catch {
73
72
  // iTerm not running or no matching sessions
74
73
  }
75
- // Try to close Terminal.app windows with this path
74
+ // Try to close Terminal.app windows with this path or issue number
76
75
  try {
77
76
  (0, child_process_1.execSync)(`osascript -e '
78
77
  tell application "Terminal"
79
78
  repeat with w in windows
80
- if name of w contains "${folderName}" then
79
+ set windowName to name of w
80
+ if windowName contains "${folderName}" or windowName contains "${issuePattern}" then
81
81
  close w
82
82
  end if
83
83
  end repeat
@@ -88,6 +88,16 @@ function closeWindowsWithPath(folderPath) {
88
88
  // Terminal not running or no matching windows
89
89
  }
90
90
  // Try to close VS Code windows with this path
91
+ try {
92
+ // Use VS Code CLI to close the folder if it's open
93
+ (0, child_process_1.execSync)(`code --folder-uri "file://${folderPath}" --command "workbench.action.closeWindow"`, {
94
+ stdio: 'pipe',
95
+ timeout: 3000
96
+ });
97
+ }
98
+ catch {
99
+ // VS Code CLI method failed, try AppleScript
100
+ }
91
101
  try {
92
102
  (0, child_process_1.execSync)(`osascript -e '
93
103
  tell application "System Events"
@@ -170,13 +180,33 @@ async function cleanAllCommand() {
170
180
  const spinner = (0, ora_1.default)(`Cleaning issue #${wt.issueNumber}...`).start();
171
181
  try {
172
182
  // Close terminal and VS Code windows for this worktree
173
- closeWindowsWithPath(wt.path);
183
+ try {
184
+ closeWindowsWithPath(wt.path, wt.issueNumber);
185
+ // Give windows time to close before removing folder
186
+ await new Promise((resolve) => setTimeout(resolve, 500));
187
+ }
188
+ catch {
189
+ // Ignore errors closing windows
190
+ }
174
191
  // Remove worktree
175
192
  if (fs.existsSync(wt.path)) {
176
- (0, child_process_1.execSync)(`git worktree remove "${wt.path}" --force`, {
177
- cwd: projectRoot,
178
- stdio: 'pipe',
179
- });
193
+ try {
194
+ (0, child_process_1.execSync)(`git worktree remove "${wt.path}" --force`, {
195
+ cwd: projectRoot,
196
+ stdio: 'pipe',
197
+ });
198
+ }
199
+ catch {
200
+ // If git worktree remove fails, try removing directory manually with rm -rf
201
+ // This handles locked files better than fs.rmSync
202
+ try {
203
+ (0, child_process_1.execSync)(`rm -rf "${wt.path}"`, { stdio: 'pipe' });
204
+ }
205
+ catch {
206
+ fs.rmSync(wt.path, { recursive: true, force: true });
207
+ }
208
+ (0, child_process_1.execSync)('git worktree prune', { cwd: projectRoot, stdio: 'pipe' });
209
+ }
180
210
  }
181
211
  // Delete branch
182
212
  try {
@@ -191,7 +221,7 @@ async function cleanAllCommand() {
191
221
  spinner.succeed(`Cleaned issue #${wt.issueNumber}`);
192
222
  }
193
223
  catch (error) {
194
- spinner.fail(`Failed to clean issue #${wt.issueNumber}`);
224
+ spinner.fail(`Failed to clean issue #${wt.issueNumber}: ${error}`);
195
225
  }
196
226
  }
197
227
  // Prune stale worktrees
@@ -200,18 +230,46 @@ async function cleanAllCommand() {
200
230
  console.log(chalk_1.default.green(`✅ Cleaned up ${worktrees.length} issue worktree(s)!`));
201
231
  }
202
232
  async function cleanCommand(issueNumber) {
203
- const spinner = (0, ora_1.default)(`Fetching issue #${issueNumber}...`).start();
204
- const issue = (0, github_1.getIssue)(issueNumber);
205
- if (!issue) {
206
- spinner.fail(`Could not find issue #${issueNumber}`);
207
- process.exit(1);
208
- }
209
- spinner.succeed(`Found issue #${issueNumber}`);
210
233
  const projectRoot = (0, git_1.getProjectRoot)();
211
234
  const projectName = (0, git_1.getProjectName)();
212
- const branchSlug = (0, helpers_1.slugify)(issue.title);
213
- const branchName = `issue-${issueNumber}-${branchSlug}`;
214
- const worktreePath = path.join(path.dirname(projectRoot), `${projectName}-${branchName}`);
235
+ // Find the worktree for this issue number (don't need to fetch from GitHub)
236
+ const worktrees = getIssueWorktrees();
237
+ const worktree = worktrees.find((wt) => wt.issueNumber === String(issueNumber));
238
+ if (!worktree) {
239
+ // Try to find by looking for the branch pattern
240
+ const branchPattern = `issue-${issueNumber}-`;
241
+ const output = (0, git_1.exec)('git branch', projectRoot);
242
+ const branches = output.split('\n').map((b) => b.trim().replace('* ', ''));
243
+ const matchingBranch = branches.find((b) => b.startsWith(branchPattern));
244
+ if (!matchingBranch) {
245
+ console.log(chalk_1.default.red(`\n❌ No worktree or branch found for issue #${issueNumber}`));
246
+ return;
247
+ }
248
+ // Found a branch but no worktree - just delete the branch
249
+ console.log(chalk_1.default.bold(`\n🧹 Cleaning up issue #${issueNumber}`));
250
+ console.log(chalk_1.default.dim(` Branch: ${matchingBranch}`));
251
+ console.log(chalk_1.default.dim(` (No worktree found)`));
252
+ const { confirm } = await inquirer_1.default.prompt([
253
+ {
254
+ type: 'confirm',
255
+ name: 'confirm',
256
+ message: 'Delete branch?',
257
+ default: false,
258
+ },
259
+ ]);
260
+ if (confirm) {
261
+ try {
262
+ (0, child_process_1.execSync)(`git branch -D "${matchingBranch}"`, { cwd: projectRoot, stdio: 'pipe' });
263
+ console.log(chalk_1.default.green('\n✅ Branch deleted!'));
264
+ }
265
+ catch {
266
+ console.log(chalk_1.default.yellow('\n⚠️ Could not delete branch'));
267
+ }
268
+ }
269
+ return;
270
+ }
271
+ const branchName = worktree.branch;
272
+ const worktreePath = worktree.path;
215
273
  console.log();
216
274
  console.log(chalk_1.default.bold(`🧹 Cleaning up issue #${issueNumber}`));
217
275
  console.log(chalk_1.default.dim(` Branch: ${branchName}`));
@@ -230,7 +288,16 @@ async function cleanCommand(issueNumber) {
230
288
  return;
231
289
  }
232
290
  // Close terminal and VS Code windows for this worktree
233
- closeWindowsWithPath(worktreePath);
291
+ const windowSpinner = (0, ora_1.default)('Closing terminal and VS Code windows...').start();
292
+ try {
293
+ closeWindowsWithPath(worktreePath, String(issueNumber));
294
+ // Give windows time to close before removing folder
295
+ await new Promise((resolve) => setTimeout(resolve, 500));
296
+ windowSpinner.succeed('Windows closed');
297
+ }
298
+ catch {
299
+ windowSpinner.warn('Could not close some windows');
300
+ }
234
301
  // Remove worktree
235
302
  if (fs.existsSync(worktreePath)) {
236
303
  const worktreeSpinner = (0, ora_1.default)('Removing worktree...').start();
@@ -242,7 +309,22 @@ async function cleanCommand(issueNumber) {
242
309
  worktreeSpinner.succeed('Worktree removed');
243
310
  }
244
311
  catch {
245
- worktreeSpinner.warn('Could not remove worktree (may already be removed)');
312
+ // If git worktree remove fails, try removing directory manually with rm -rf
313
+ try {
314
+ (0, child_process_1.execSync)(`rm -rf "${worktreePath}"`, { stdio: 'pipe' });
315
+ (0, child_process_1.execSync)('git worktree prune', { cwd: projectRoot, stdio: 'pipe' });
316
+ worktreeSpinner.succeed('Worktree removed (manually)');
317
+ }
318
+ catch {
319
+ try {
320
+ fs.rmSync(worktreePath, { recursive: true, force: true });
321
+ (0, child_process_1.execSync)('git worktree prune', { cwd: projectRoot, stdio: 'pipe' });
322
+ worktreeSpinner.succeed('Worktree removed (manually)');
323
+ }
324
+ catch {
325
+ worktreeSpinner.warn('Could not remove worktree directory');
326
+ }
327
+ }
246
328
  }
247
329
  }
248
330
  // Delete branch
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-issue-solver",
3
- "version": "1.6.2",
3
+ "version": "1.6.4",
4
4
  "description": "Automatically solve GitHub issues using Claude Code",
5
5
  "main": "dist/index.js",
6
6
  "bin": {