claude-issue-solver 1.7.2 → 1.8.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/dist/commands/clean.d.ts +1 -0
- package/dist/commands/clean.js +139 -0
- package/dist/index.js +6 -2
- package/package.json +1 -1
package/dist/commands/clean.d.ts
CHANGED
package/dist/commands/clean.js
CHANGED
|
@@ -38,6 +38,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.cleanAllCommand = cleanAllCommand;
|
|
40
40
|
exports.cleanCommand = cleanCommand;
|
|
41
|
+
exports.cleanMergedCommand = cleanMergedCommand;
|
|
41
42
|
const chalk_1 = __importDefault(require("chalk"));
|
|
42
43
|
const ora_1 = __importDefault(require("ora"));
|
|
43
44
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
@@ -222,11 +223,19 @@ function getIssueWorktrees() {
|
|
|
222
223
|
}
|
|
223
224
|
async function cleanAllCommand() {
|
|
224
225
|
const projectRoot = (0, git_1.getProjectRoot)();
|
|
226
|
+
const currentDir = process.cwd();
|
|
225
227
|
const worktrees = getIssueWorktrees();
|
|
226
228
|
if (worktrees.length === 0) {
|
|
227
229
|
console.log(chalk_1.default.yellow('\nNo issue worktrees found.'));
|
|
228
230
|
return;
|
|
229
231
|
}
|
|
232
|
+
// Warn if user is inside a worktree that might be deleted
|
|
233
|
+
const inWorktree = worktrees.find((wt) => currentDir.startsWith(wt.path));
|
|
234
|
+
if (inWorktree) {
|
|
235
|
+
console.log(chalk_1.default.yellow(`\n⚠️ You are inside worktree #${inWorktree.issueNumber}`));
|
|
236
|
+
console.log(chalk_1.default.yellow(` Run this command from the main project directory for best results.`));
|
|
237
|
+
console.log(chalk_1.default.dim(` cd ${projectRoot}\n`));
|
|
238
|
+
}
|
|
230
239
|
// Fetch status for all worktrees
|
|
231
240
|
const statusSpinner = (0, ora_1.default)('Fetching issue and PR status...').start();
|
|
232
241
|
const worktreesWithStatus = worktrees.map((wt) => ({
|
|
@@ -492,3 +501,133 @@ async function cleanCommand(issueNumber) {
|
|
|
492
501
|
console.log();
|
|
493
502
|
console.log(chalk_1.default.green('✅ Cleanup complete!'));
|
|
494
503
|
}
|
|
504
|
+
async function cleanMergedCommand() {
|
|
505
|
+
const projectRoot = (0, git_1.getProjectRoot)();
|
|
506
|
+
const currentDir = process.cwd();
|
|
507
|
+
const worktrees = getIssueWorktrees();
|
|
508
|
+
if (worktrees.length === 0) {
|
|
509
|
+
console.log(chalk_1.default.yellow('\nNo issue worktrees found.'));
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
// Warn if user is inside a worktree that might be deleted
|
|
513
|
+
const inWorktree = worktrees.find((wt) => currentDir.startsWith(wt.path));
|
|
514
|
+
if (inWorktree) {
|
|
515
|
+
console.log(chalk_1.default.yellow(`\n⚠️ You are inside worktree #${inWorktree.issueNumber}`));
|
|
516
|
+
console.log(chalk_1.default.yellow(` Run this command from the main project directory for best results.`));
|
|
517
|
+
console.log(chalk_1.default.dim(` cd ${projectRoot}\n`));
|
|
518
|
+
}
|
|
519
|
+
// Fetch status for all worktrees
|
|
520
|
+
const statusSpinner = (0, ora_1.default)('Fetching PR status...').start();
|
|
521
|
+
const worktreesWithStatus = worktrees.map((wt) => ({
|
|
522
|
+
...wt,
|
|
523
|
+
issueStatus: (0, github_1.getIssueStatus)(parseInt(wt.issueNumber, 10)),
|
|
524
|
+
prStatus: wt.branch ? (0, github_1.getPRForBranch)(wt.branch) : null,
|
|
525
|
+
}));
|
|
526
|
+
statusSpinner.stop();
|
|
527
|
+
// Filter to only merged PRs
|
|
528
|
+
const mergedWorktrees = worktreesWithStatus.filter((wt) => wt.prStatus?.state === 'merged');
|
|
529
|
+
if (mergedWorktrees.length === 0) {
|
|
530
|
+
console.log(chalk_1.default.yellow('\nNo worktrees with merged PRs found.'));
|
|
531
|
+
// Show what's available
|
|
532
|
+
if (worktreesWithStatus.length > 0) {
|
|
533
|
+
console.log(chalk_1.default.dim('\nExisting worktrees:'));
|
|
534
|
+
for (const wt of worktreesWithStatus) {
|
|
535
|
+
const status = getStatusLabel(wt);
|
|
536
|
+
console.log(` ${chalk_1.default.cyan(`#${wt.issueNumber}`)}\t${status}`);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
console.log(chalk_1.default.bold(`\n🧹 Cleaning ${mergedWorktrees.length} worktree(s) with merged PRs:\n`));
|
|
542
|
+
for (const wt of mergedWorktrees) {
|
|
543
|
+
console.log(` ${chalk_1.default.cyan(`#${wt.issueNumber}`)}\t${chalk_1.default.green('✓ PR merged')}`);
|
|
544
|
+
if (wt.branch) {
|
|
545
|
+
console.log(chalk_1.default.dim(` \t${wt.branch}`));
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
console.log();
|
|
549
|
+
for (const wt of mergedWorktrees) {
|
|
550
|
+
const spinner = (0, ora_1.default)(`Cleaning issue #${wt.issueNumber}...`).start();
|
|
551
|
+
try {
|
|
552
|
+
// Close terminal and VS Code windows for this worktree
|
|
553
|
+
try {
|
|
554
|
+
closeWindowsWithPath(wt.path, wt.issueNumber);
|
|
555
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
556
|
+
}
|
|
557
|
+
catch {
|
|
558
|
+
// Ignore errors closing windows
|
|
559
|
+
}
|
|
560
|
+
// Remove worktree/folder
|
|
561
|
+
const isOrphaned = !wt.branch;
|
|
562
|
+
// Try git worktree remove first (only if not orphaned)
|
|
563
|
+
if (!isOrphaned && fs.existsSync(wt.path)) {
|
|
564
|
+
try {
|
|
565
|
+
(0, child_process_1.execSync)(`git worktree remove "${wt.path}" --force`, {
|
|
566
|
+
cwd: projectRoot,
|
|
567
|
+
stdio: 'pipe',
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
catch {
|
|
571
|
+
// Ignore - we'll force delete below
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
// Always try to force delete the folder
|
|
575
|
+
if (fs.existsSync(wt.path)) {
|
|
576
|
+
try {
|
|
577
|
+
(0, child_process_1.execSync)(`/bin/rm -rf "${wt.path}"`, { stdio: 'pipe', timeout: 10000 });
|
|
578
|
+
}
|
|
579
|
+
catch {
|
|
580
|
+
try {
|
|
581
|
+
(0, child_process_1.execSync)(`rm -rf "${wt.path}"`, { shell: '/bin/bash', stdio: 'pipe', timeout: 10000 });
|
|
582
|
+
}
|
|
583
|
+
catch {
|
|
584
|
+
try {
|
|
585
|
+
fs.rmSync(wt.path, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 });
|
|
586
|
+
}
|
|
587
|
+
catch {
|
|
588
|
+
// Will report failure below
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
// Prune git worktrees
|
|
594
|
+
try {
|
|
595
|
+
(0, child_process_1.execSync)('git worktree prune', { cwd: projectRoot, stdio: 'pipe' });
|
|
596
|
+
}
|
|
597
|
+
catch {
|
|
598
|
+
// Ignore
|
|
599
|
+
}
|
|
600
|
+
// Delete branch (if we have one)
|
|
601
|
+
if (wt.branch) {
|
|
602
|
+
try {
|
|
603
|
+
(0, child_process_1.execSync)(`git branch -D "${wt.branch}"`, {
|
|
604
|
+
cwd: projectRoot,
|
|
605
|
+
stdio: 'pipe',
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
catch {
|
|
609
|
+
// Branch may already be deleted
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
// Check if cleanup was successful
|
|
613
|
+
if (fs.existsSync(wt.path)) {
|
|
614
|
+
spinner.warn(`Cleaned issue #${wt.issueNumber} (folder may remain: ${wt.path})`);
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
spinner.succeed(`Cleaned issue #${wt.issueNumber}`);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
catch (error) {
|
|
621
|
+
spinner.fail(`Failed to clean issue #${wt.issueNumber}: ${error}`);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
// Prune stale worktrees
|
|
625
|
+
try {
|
|
626
|
+
(0, child_process_1.execSync)('git worktree prune', { cwd: projectRoot, stdio: 'pipe' });
|
|
627
|
+
}
|
|
628
|
+
catch {
|
|
629
|
+
// May fail if current directory was deleted
|
|
630
|
+
}
|
|
631
|
+
console.log();
|
|
632
|
+
console.log(chalk_1.default.green(`✅ Cleaned up ${mergedWorktrees.length} merged worktree(s)!`));
|
|
633
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -76,9 +76,13 @@ program
|
|
|
76
76
|
.command('clean [issue]')
|
|
77
77
|
.alias('rm')
|
|
78
78
|
.option('-a, --all', 'Clean all issue worktrees')
|
|
79
|
-
.
|
|
79
|
+
.option('-m, --merged', 'Clean only worktrees with merged PRs (no confirmation)')
|
|
80
|
+
.description('Remove worktree and branch for an issue (or all with --all, or merged with --merged)')
|
|
80
81
|
.action(async (issue, options) => {
|
|
81
|
-
if (options.
|
|
82
|
+
if (options.merged) {
|
|
83
|
+
await (0, clean_1.cleanMergedCommand)();
|
|
84
|
+
}
|
|
85
|
+
else if (options.all) {
|
|
82
86
|
await (0, clean_1.cleanAllCommand)();
|
|
83
87
|
}
|
|
84
88
|
else if (issue) {
|