claude-issue-solver 1.4.0 ā 1.6.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.
- package/dist/commands/clean.js +45 -0
- package/dist/commands/go.d.ts +1 -0
- package/dist/commands/go.js +149 -0
- package/dist/index.js +13 -0
- package/package.json +1 -1
package/dist/commands/clean.js
CHANGED
|
@@ -43,10 +43,51 @@ 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");
|
|
49
50
|
const helpers_1 = require("../utils/helpers");
|
|
51
|
+
function closeTerminalWithPath(folderPath) {
|
|
52
|
+
if (os.platform() !== 'darwin')
|
|
53
|
+
return;
|
|
54
|
+
const folderName = path.basename(folderPath);
|
|
55
|
+
// Try to close iTerm2 tabs/windows with this path
|
|
56
|
+
try {
|
|
57
|
+
(0, child_process_1.execSync)(`osascript -e '
|
|
58
|
+
tell application "iTerm"
|
|
59
|
+
repeat with w in windows
|
|
60
|
+
repeat with t in tabs of w
|
|
61
|
+
repeat with s in sessions of t
|
|
62
|
+
set sessionName to name of s
|
|
63
|
+
if sessionName contains "${folderName}" then
|
|
64
|
+
close s
|
|
65
|
+
end if
|
|
66
|
+
end repeat
|
|
67
|
+
end repeat
|
|
68
|
+
end repeat
|
|
69
|
+
end tell
|
|
70
|
+
'`, { stdio: 'pipe' });
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// iTerm not running or no matching sessions
|
|
74
|
+
}
|
|
75
|
+
// Try to close Terminal.app windows with this path
|
|
76
|
+
try {
|
|
77
|
+
(0, child_process_1.execSync)(`osascript -e '
|
|
78
|
+
tell application "Terminal"
|
|
79
|
+
repeat with w in windows
|
|
80
|
+
if name of w contains "${folderName}" then
|
|
81
|
+
close w
|
|
82
|
+
end if
|
|
83
|
+
end repeat
|
|
84
|
+
end tell
|
|
85
|
+
'`, { stdio: 'pipe' });
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// Terminal not running or no matching windows
|
|
89
|
+
}
|
|
90
|
+
}
|
|
50
91
|
function getIssueWorktrees() {
|
|
51
92
|
const projectRoot = (0, git_1.getProjectRoot)();
|
|
52
93
|
const projectName = (0, git_1.getProjectName)();
|
|
@@ -107,6 +148,8 @@ async function cleanAllCommand() {
|
|
|
107
148
|
for (const wt of worktrees) {
|
|
108
149
|
const spinner = (0, ora_1.default)(`Cleaning issue #${wt.issueNumber}...`).start();
|
|
109
150
|
try {
|
|
151
|
+
// Close terminal windows for this worktree
|
|
152
|
+
closeTerminalWithPath(wt.path);
|
|
110
153
|
// Remove worktree
|
|
111
154
|
if (fs.existsSync(wt.path)) {
|
|
112
155
|
(0, child_process_1.execSync)(`git worktree remove "${wt.path}" --force`, {
|
|
@@ -165,6 +208,8 @@ async function cleanCommand(issueNumber) {
|
|
|
165
208
|
console.log(chalk_1.default.dim('Cancelled.'));
|
|
166
209
|
return;
|
|
167
210
|
}
|
|
211
|
+
// Close terminal windows for this worktree
|
|
212
|
+
closeTerminalWithPath(worktreePath);
|
|
168
213
|
// Remove worktree
|
|
169
214
|
if (fs.existsSync(worktreePath)) {
|
|
170
215
|
const worktreeSpinner = (0, ora_1.default)('Removing worktree...').start();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function goCommand(issueNumber?: number): Promise<void>;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.goCommand = goCommand;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
9
|
+
const child_process_1 = require("child_process");
|
|
10
|
+
const git_1 = require("../utils/git");
|
|
11
|
+
function getIssueWorktrees() {
|
|
12
|
+
const projectRoot = (0, git_1.getProjectRoot)();
|
|
13
|
+
const projectName = (0, git_1.getProjectName)();
|
|
14
|
+
const worktrees = [];
|
|
15
|
+
// Get all worktrees from git
|
|
16
|
+
const output = (0, git_1.exec)('git worktree list --porcelain', projectRoot);
|
|
17
|
+
if (!output)
|
|
18
|
+
return worktrees;
|
|
19
|
+
const lines = output.split('\n');
|
|
20
|
+
let currentPath = '';
|
|
21
|
+
let currentBranch = '';
|
|
22
|
+
for (const line of lines) {
|
|
23
|
+
if (line.startsWith('worktree ')) {
|
|
24
|
+
currentPath = line.replace('worktree ', '');
|
|
25
|
+
}
|
|
26
|
+
else if (line.startsWith('branch refs/heads/')) {
|
|
27
|
+
currentBranch = line.replace('branch refs/heads/', '');
|
|
28
|
+
// Check if this is an issue branch
|
|
29
|
+
const match = currentBranch.match(/^issue-(\d+)-/);
|
|
30
|
+
if (match && currentPath.includes(`${projectName}-issue-`)) {
|
|
31
|
+
worktrees.push({
|
|
32
|
+
path: currentPath,
|
|
33
|
+
branch: currentBranch,
|
|
34
|
+
issueNumber: match[1],
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return worktrees;
|
|
40
|
+
}
|
|
41
|
+
function getPRForBranch(branch) {
|
|
42
|
+
try {
|
|
43
|
+
const output = (0, child_process_1.execSync)(`gh pr list --head "${branch}" --json url --jq '.[0].url'`, {
|
|
44
|
+
encoding: 'utf-8',
|
|
45
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
46
|
+
}).trim();
|
|
47
|
+
return output || null;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function goCommand(issueNumber) {
|
|
54
|
+
const worktrees = getIssueWorktrees();
|
|
55
|
+
if (worktrees.length === 0) {
|
|
56
|
+
console.log(chalk_1.default.yellow('\nNo issue worktrees found.'));
|
|
57
|
+
console.log(chalk_1.default.dim('Run `claude-issue <number>` to start working on an issue.'));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
let selectedWorktree;
|
|
61
|
+
if (issueNumber) {
|
|
62
|
+
// Find specific worktree
|
|
63
|
+
const found = worktrees.find((wt) => wt.issueNumber === String(issueNumber));
|
|
64
|
+
if (!found) {
|
|
65
|
+
console.log(chalk_1.default.red(`\nā No worktree found for issue #${issueNumber}`));
|
|
66
|
+
console.log(chalk_1.default.dim('\nAvailable worktrees:'));
|
|
67
|
+
for (const wt of worktrees) {
|
|
68
|
+
console.log(chalk_1.default.dim(` #${wt.issueNumber}: ${wt.path}`));
|
|
69
|
+
}
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
selectedWorktree = found;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// Show selection
|
|
76
|
+
console.log(chalk_1.default.bold('\nš Issue worktrees:\n'));
|
|
77
|
+
const choices = worktrees.map((wt) => ({
|
|
78
|
+
name: `#${wt.issueNumber}\t${wt.branch}`,
|
|
79
|
+
value: wt,
|
|
80
|
+
}));
|
|
81
|
+
choices.push({
|
|
82
|
+
name: chalk_1.default.dim('Cancel'),
|
|
83
|
+
value: null,
|
|
84
|
+
});
|
|
85
|
+
const { selected } = await inquirer_1.default.prompt([
|
|
86
|
+
{
|
|
87
|
+
type: 'list',
|
|
88
|
+
name: 'selected',
|
|
89
|
+
message: 'Select a worktree to open:',
|
|
90
|
+
choices,
|
|
91
|
+
pageSize: 15,
|
|
92
|
+
},
|
|
93
|
+
]);
|
|
94
|
+
if (!selected) {
|
|
95
|
+
console.log(chalk_1.default.dim('Cancelled.'));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
selectedWorktree = selected;
|
|
99
|
+
}
|
|
100
|
+
// Get PR info
|
|
101
|
+
const prUrl = getPRForBranch(selectedWorktree.branch);
|
|
102
|
+
console.log();
|
|
103
|
+
console.log(chalk_1.default.bold(`š Issue #${selectedWorktree.issueNumber}`));
|
|
104
|
+
console.log(chalk_1.default.dim(` Path: ${selectedWorktree.path}`));
|
|
105
|
+
console.log(chalk_1.default.dim(` Branch: ${selectedWorktree.branch}`));
|
|
106
|
+
if (prUrl) {
|
|
107
|
+
console.log(chalk_1.default.cyan(` PR: ${prUrl}`));
|
|
108
|
+
}
|
|
109
|
+
console.log();
|
|
110
|
+
// Ask what to do
|
|
111
|
+
const actions = [
|
|
112
|
+
{ name: 'š Open in VS Code', value: 'vscode' },
|
|
113
|
+
{ name: 'š Open in Finder', value: 'finder' },
|
|
114
|
+
{ name: 'š» Print cd command', value: 'cd' },
|
|
115
|
+
];
|
|
116
|
+
if (prUrl) {
|
|
117
|
+
actions.unshift({ name: 'š Open PR in browser', value: 'pr' });
|
|
118
|
+
}
|
|
119
|
+
actions.push({ name: chalk_1.default.dim('Cancel'), value: 'cancel' });
|
|
120
|
+
const { action } = await inquirer_1.default.prompt([
|
|
121
|
+
{
|
|
122
|
+
type: 'list',
|
|
123
|
+
name: 'action',
|
|
124
|
+
message: 'What would you like to do?',
|
|
125
|
+
choices: actions,
|
|
126
|
+
},
|
|
127
|
+
]);
|
|
128
|
+
switch (action) {
|
|
129
|
+
case 'pr':
|
|
130
|
+
console.log(chalk_1.default.dim(`\nOpening PR in browser...`));
|
|
131
|
+
(0, child_process_1.execSync)(`open "${prUrl}"`, { stdio: 'pipe' });
|
|
132
|
+
break;
|
|
133
|
+
case 'vscode':
|
|
134
|
+
console.log(chalk_1.default.dim(`\nOpening in VS Code...`));
|
|
135
|
+
(0, child_process_1.execSync)(`code "${selectedWorktree.path}"`, { stdio: 'pipe' });
|
|
136
|
+
break;
|
|
137
|
+
case 'finder':
|
|
138
|
+
console.log(chalk_1.default.dim(`\nOpening in Finder...`));
|
|
139
|
+
(0, child_process_1.execSync)(`open "${selectedWorktree.path}"`, { stdio: 'pipe' });
|
|
140
|
+
break;
|
|
141
|
+
case 'cd':
|
|
142
|
+
console.log(chalk_1.default.dim(`\nRun this command:\n`));
|
|
143
|
+
console.log(chalk_1.default.cyan(`cd "${selectedWorktree.path}"`));
|
|
144
|
+
break;
|
|
145
|
+
case 'cancel':
|
|
146
|
+
console.log(chalk_1.default.dim('Cancelled.'));
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ const solve_1 = require("./commands/solve");
|
|
|
13
13
|
const pr_1 = require("./commands/pr");
|
|
14
14
|
const clean_1 = require("./commands/clean");
|
|
15
15
|
const select_1 = require("./commands/select");
|
|
16
|
+
const go_1 = require("./commands/go");
|
|
16
17
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
17
18
|
const packageJson = require('../package.json');
|
|
18
19
|
const program = new commander_1.Command();
|
|
@@ -93,4 +94,16 @@ program
|
|
|
93
94
|
await (0, clean_1.cleanAllCommand)();
|
|
94
95
|
}
|
|
95
96
|
});
|
|
97
|
+
// Go command - navigate to worktree and open PR
|
|
98
|
+
program
|
|
99
|
+
.command('go [issue]')
|
|
100
|
+
.description('Navigate to an issue worktree, open VS Code, or view PR')
|
|
101
|
+
.action(async (issue) => {
|
|
102
|
+
const issueNumber = issue ? parseInt(issue, 10) : undefined;
|
|
103
|
+
if (issue && isNaN(issueNumber)) {
|
|
104
|
+
console.log(chalk_1.default.red(`ā Invalid issue number: ${issue}`));
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
await (0, go_1.goCommand)(issueNumber);
|
|
108
|
+
});
|
|
96
109
|
program.parse();
|