claude-issue-solver 1.6.4 → 1.6.5

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.
@@ -124,30 +124,57 @@ function getIssueWorktrees() {
124
124
  const projectName = (0, git_1.getProjectName)();
125
125
  const parentDir = path.dirname(projectRoot);
126
126
  const worktrees = [];
127
+ const foundPaths = new Set();
127
128
  // Get all worktrees from git
128
129
  const output = (0, git_1.exec)('git worktree list --porcelain', projectRoot);
129
- if (!output)
130
- return worktrees;
131
- const lines = output.split('\n');
132
- let currentPath = '';
133
- let currentBranch = '';
134
- for (const line of lines) {
135
- if (line.startsWith('worktree ')) {
136
- currentPath = line.replace('worktree ', '');
130
+ if (output) {
131
+ const lines = output.split('\n');
132
+ let currentPath = '';
133
+ let currentBranch = '';
134
+ for (const line of lines) {
135
+ if (line.startsWith('worktree ')) {
136
+ currentPath = line.replace('worktree ', '');
137
+ }
138
+ else if (line.startsWith('branch refs/heads/')) {
139
+ currentBranch = line.replace('branch refs/heads/', '');
140
+ // Check if this is an issue branch
141
+ const match = currentBranch.match(/^issue-(\d+)-/);
142
+ if (match && currentPath.includes(`${projectName}-issue-`)) {
143
+ worktrees.push({
144
+ path: currentPath,
145
+ branch: currentBranch,
146
+ issueNumber: match[1],
147
+ });
148
+ foundPaths.add(currentPath);
149
+ }
150
+ }
137
151
  }
138
- else if (line.startsWith('branch refs/heads/')) {
139
- currentBranch = line.replace('branch refs/heads/', '');
140
- // Check if this is an issue branch
141
- const match = currentBranch.match(/^issue-(\d+)-/);
142
- if (match && currentPath.includes(`${projectName}-issue-`)) {
143
- worktrees.push({
144
- path: currentPath,
145
- branch: currentBranch,
146
- issueNumber: match[1],
147
- });
152
+ }
153
+ // Also check for orphaned folders (folders that exist but aren't in git worktree list)
154
+ // This can happen when git worktree remove fails but the folder remains
155
+ try {
156
+ const folderPattern = `${projectName}-issue-`;
157
+ const entries = fs.readdirSync(parentDir, { withFileTypes: true });
158
+ for (const entry of entries) {
159
+ if (entry.isDirectory() && entry.name.startsWith(folderPattern)) {
160
+ const folderPath = path.join(parentDir, entry.name);
161
+ if (!foundPaths.has(folderPath)) {
162
+ // Extract issue number from folder name (e.g., "project-issue-38-slug")
163
+ const match = entry.name.match(new RegExp(`${projectName}-issue-(\\d+)-`));
164
+ if (match) {
165
+ worktrees.push({
166
+ path: folderPath,
167
+ branch: '', // No branch known for orphaned folders
168
+ issueNumber: match[1],
169
+ });
170
+ }
171
+ }
148
172
  }
149
173
  }
150
174
  }
175
+ catch {
176
+ // Ignore errors reading parent directory
177
+ }
151
178
  return worktrees;
152
179
  }
153
180
  async function cleanAllCommand() {
@@ -159,7 +186,7 @@ async function cleanAllCommand() {
159
186
  }
160
187
  console.log(chalk_1.default.bold('\n🧹 Found issue worktrees:\n'));
161
188
  for (const wt of worktrees) {
162
- console.log(` ${chalk_1.default.cyan(`#${wt.issueNumber}`)}\t${wt.branch}`);
189
+ console.log(` ${chalk_1.default.cyan(`#${wt.issueNumber}`)}\t${wt.branch || chalk_1.default.yellow('(orphaned folder)')}`);
163
190
  console.log(chalk_1.default.dim(` \t${wt.path}`));
164
191
  console.log();
165
192
  }
@@ -208,15 +235,17 @@ async function cleanAllCommand() {
208
235
  (0, child_process_1.execSync)('git worktree prune', { cwd: projectRoot, stdio: 'pipe' });
209
236
  }
210
237
  }
211
- // Delete branch
212
- try {
213
- (0, child_process_1.execSync)(`git branch -D "${wt.branch}"`, {
214
- cwd: projectRoot,
215
- stdio: 'pipe',
216
- });
217
- }
218
- catch {
219
- // Branch may already be deleted
238
+ // Delete branch (if we have one)
239
+ if (wt.branch) {
240
+ try {
241
+ (0, child_process_1.execSync)(`git branch -D "${wt.branch}"`, {
242
+ cwd: projectRoot,
243
+ stdio: 'pipe',
244
+ });
245
+ }
246
+ catch {
247
+ // Branch may already be deleted
248
+ }
220
249
  }
221
250
  spinner.succeed(`Cleaned issue #${wt.issueNumber}`);
222
251
  }
@@ -232,7 +261,9 @@ async function cleanAllCommand() {
232
261
  async function cleanCommand(issueNumber) {
233
262
  const projectRoot = (0, git_1.getProjectRoot)();
234
263
  const projectName = (0, git_1.getProjectName)();
264
+ const parentDir = path.dirname(projectRoot);
235
265
  // Find the worktree for this issue number (don't need to fetch from GitHub)
266
+ // This now also includes orphaned folders
236
267
  const worktrees = getIssueWorktrees();
237
268
  const worktree = worktrees.find((wt) => wt.issueNumber === String(issueNumber));
238
269
  if (!worktree) {
@@ -242,7 +273,7 @@ async function cleanCommand(issueNumber) {
242
273
  const branches = output.split('\n').map((b) => b.trim().replace('* ', ''));
243
274
  const matchingBranch = branches.find((b) => b.startsWith(branchPattern));
244
275
  if (!matchingBranch) {
245
- console.log(chalk_1.default.red(`\nāŒ No worktree or branch found for issue #${issueNumber}`));
276
+ console.log(chalk_1.default.red(`\nāŒ No worktree, folder, or branch found for issue #${issueNumber}`));
246
277
  return;
247
278
  }
248
279
  // Found a branch but no worktree - just delete the branch
@@ -270,16 +301,22 @@ async function cleanCommand(issueNumber) {
270
301
  }
271
302
  const branchName = worktree.branch;
272
303
  const worktreePath = worktree.path;
304
+ const isOrphaned = !branchName;
273
305
  console.log();
274
306
  console.log(chalk_1.default.bold(`🧹 Cleaning up issue #${issueNumber}`));
275
- console.log(chalk_1.default.dim(` Branch: ${branchName}`));
276
- console.log(chalk_1.default.dim(` Worktree: ${worktreePath}`));
307
+ if (isOrphaned) {
308
+ console.log(chalk_1.default.yellow(` (Orphaned folder - no git worktree reference)`));
309
+ }
310
+ else {
311
+ console.log(chalk_1.default.dim(` Branch: ${branchName}`));
312
+ }
313
+ console.log(chalk_1.default.dim(` Folder: ${worktreePath}`));
277
314
  console.log();
278
315
  const { confirm } = await inquirer_1.default.prompt([
279
316
  {
280
317
  type: 'confirm',
281
318
  name: 'confirm',
282
- message: 'Remove worktree and delete branch?',
319
+ message: isOrphaned ? 'Remove orphaned folder?' : 'Remove worktree and delete branch?',
283
320
  default: false,
284
321
  },
285
322
  ]);
@@ -327,17 +364,19 @@ async function cleanCommand(issueNumber) {
327
364
  }
328
365
  }
329
366
  }
330
- // Delete branch
331
- const branchSpinner = (0, ora_1.default)('Deleting branch...').start();
332
- try {
333
- (0, child_process_1.execSync)(`git branch -D "${branchName}"`, {
334
- cwd: projectRoot,
335
- stdio: 'pipe',
336
- });
337
- branchSpinner.succeed('Branch deleted');
338
- }
339
- catch {
340
- branchSpinner.warn('Could not delete branch (may already be deleted)');
367
+ // Delete branch (if we have one)
368
+ if (branchName) {
369
+ const branchSpinner = (0, ora_1.default)('Deleting branch...').start();
370
+ try {
371
+ (0, child_process_1.execSync)(`git branch -D "${branchName}"`, {
372
+ cwd: projectRoot,
373
+ stdio: 'pipe',
374
+ });
375
+ branchSpinner.succeed('Branch deleted');
376
+ }
377
+ catch {
378
+ branchSpinner.warn('Could not delete branch (may already be deleted)');
379
+ }
341
380
  }
342
381
  console.log();
343
382
  console.log(chalk_1.default.green('āœ… Cleanup complete!'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-issue-solver",
3
- "version": "1.6.4",
3
+ "version": "1.6.5",
4
4
  "description": "Automatically solve GitHub issues using Claude Code",
5
5
  "main": "dist/index.js",
6
6
  "bin": {