claude-issue-solver 1.9.0 โ 1.10.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/README.md +92 -19
- package/dist/commands/new.d.ts +4 -0
- package/dist/commands/new.js +23 -0
- package/dist/index.js +10 -0
- package/dist/utils/github.d.ts +1 -0
- package/dist/utils/github.js +24 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,6 +26,7 @@ This CLI tool fetches an issue from your repo, creates a worktree, opens Claude
|
|
|
26
26
|
$ claude-issue
|
|
27
27
|
|
|
28
28
|
Open issues for my-project:
|
|
29
|
+
(2 issues with open PRs hidden)
|
|
29
30
|
|
|
30
31
|
? Select an issue to solve:
|
|
31
32
|
โฏ #42 Add dark mode support
|
|
@@ -45,11 +46,13 @@ Open issues for my-project:
|
|
|
45
46
|
|
|
46
47
|
## Features
|
|
47
48
|
|
|
48
|
-
- ๐ฏ **Interactive issue selection** - Lists open issues with arrow-key navigation
|
|
49
|
+
- ๐ฏ **Interactive issue selection** - Lists open issues with arrow-key navigation (hides issues with open PRs)
|
|
50
|
+
- โจ **Create and solve** - Create new issues and start solving them immediately
|
|
49
51
|
- ๐ฟ **Worktree isolation** - Each issue gets its own worktree, work on multiple issues in parallel
|
|
50
|
-
- ๐ค **
|
|
51
|
-
-
|
|
52
|
-
-
|
|
52
|
+
- ๐ค **Real-time PR creation** - Automatically creates/updates PR as Claude commits changes
|
|
53
|
+
- ๐งน **Smart cleanup** - Auto-clean merged PRs, close VS Code/terminal windows on macOS
|
|
54
|
+
- ๐ **Monorepo support** - Recursively copies all `.env*` files, symlinks `node_modules`
|
|
55
|
+
- ๐ป **Cross-platform terminals** - iTerm2, Terminal.app (macOS), gnome-terminal, xterm, konsole (Linux)
|
|
53
56
|
|
|
54
57
|
## Requirements
|
|
55
58
|
|
|
@@ -87,31 +90,60 @@ claude-issue 42
|
|
|
87
90
|
|
|
88
91
|
# List open issues
|
|
89
92
|
claude-issue list
|
|
93
|
+
claude-issue ls
|
|
94
|
+
|
|
95
|
+
# Create a new issue and solve it immediately
|
|
96
|
+
claude-issue new "Add dark mode support"
|
|
97
|
+
claude-issue new "Fix login bug" -b "Users can't login on mobile"
|
|
98
|
+
claude-issue new "Fix crash" -l bug -l priority
|
|
90
99
|
|
|
91
100
|
# Create PR for a solved issue (if you skipped it earlier)
|
|
92
101
|
claude-issue pr 42
|
|
93
102
|
|
|
94
|
-
# Clean up worktree and branch
|
|
95
|
-
claude-issue clean 42
|
|
96
|
-
|
|
97
|
-
# Clean all worktrees (
|
|
98
|
-
claude-issue clean
|
|
103
|
+
# Clean up worktree and branch
|
|
104
|
+
claude-issue clean 42 # Clean specific issue
|
|
105
|
+
claude-issue clean # Interactive selection
|
|
106
|
+
claude-issue clean --all # Clean all worktrees (with confirmation)
|
|
107
|
+
claude-issue clean --merged # Auto-clean only merged PRs (no confirmation)
|
|
99
108
|
|
|
100
109
|
# Navigate to a worktree or open its PR
|
|
101
|
-
claude-issue go
|
|
110
|
+
claude-issue go # Interactive selection
|
|
111
|
+
claude-issue go 42 # Go to specific issue
|
|
102
112
|
|
|
103
113
|
# Show help
|
|
104
114
|
claude-issue --help
|
|
105
115
|
```
|
|
106
116
|
|
|
117
|
+
## Commands Reference
|
|
118
|
+
|
|
119
|
+
| Command | Alias | Description |
|
|
120
|
+
|---------|-------|-------------|
|
|
121
|
+
| `claude-issue` | - | Interactive issue selection |
|
|
122
|
+
| `claude-issue <number>` | - | Solve specific issue |
|
|
123
|
+
| `claude-issue new <title>` | - | Create issue and solve it |
|
|
124
|
+
| `claude-issue list` | `ls` | List open issues |
|
|
125
|
+
| `claude-issue pr <number>` | - | Create PR for solved issue |
|
|
126
|
+
| `claude-issue clean [number]` | `rm` | Remove worktree and branch |
|
|
127
|
+
| `claude-issue go [number]` | - | Navigate to worktree |
|
|
128
|
+
|
|
129
|
+
### Command Options
|
|
130
|
+
|
|
131
|
+
**`new` command:**
|
|
132
|
+
- `-b, --body <text>` - Issue description
|
|
133
|
+
- `-l, --label <name>` - Add label (can be used multiple times)
|
|
134
|
+
|
|
135
|
+
**`clean` command:**
|
|
136
|
+
- `-a, --all` - Clean all issue worktrees (with confirmation)
|
|
137
|
+
- `-m, --merged` - Clean only worktrees with merged PRs (no confirmation)
|
|
138
|
+
|
|
107
139
|
## How it works
|
|
108
140
|
|
|
109
141
|
1. **Fetches issue** - Gets title and description from GitHub
|
|
110
142
|
2. **Creates worktree** - Makes a new git worktree with branch `issue-{number}-{slug}`
|
|
111
|
-
3. **Sets up environment** -
|
|
143
|
+
3. **Sets up environment** - Recursively copies all `.env*` files, symlinks `node_modules`
|
|
112
144
|
4. **Opens Claude** - Launches Claude Code in a new terminal with the issue as context
|
|
113
|
-
5. **
|
|
114
|
-
6. **
|
|
145
|
+
5. **Real-time PR creation** - Background watcher creates PR on first commit, pushes updates on subsequent commits
|
|
146
|
+
6. **Interactive session** - Claude stays open so you can ask for changes
|
|
115
147
|
|
|
116
148
|
## Workflow
|
|
117
149
|
|
|
@@ -142,24 +174,65 @@ claude-issue --help
|
|
|
142
174
|
โ
|
|
143
175
|
โผ
|
|
144
176
|
โโโโโโโโโโโโโโโโโโโ
|
|
145
|
-
โ
|
|
177
|
+
โ Auto-create PR โ
|
|
146
178
|
โ "Closes #42" โ
|
|
147
179
|
โโโโโโโโโโฌโโโโโโโโโ
|
|
148
180
|
โ
|
|
149
181
|
โผ
|
|
150
182
|
โโโโโโโโโโโโโโโโโโโ
|
|
151
183
|
โ claude-issue โ
|
|
152
|
-
โ clean
|
|
184
|
+
โ clean --merged โ
|
|
153
185
|
โโโโโโโโโโโโโโโโโโโ
|
|
154
186
|
```
|
|
155
187
|
|
|
188
|
+
## Smart Features
|
|
189
|
+
|
|
190
|
+
### Issue Filtering
|
|
191
|
+
When selecting issues, the tool automatically hides issues that already have open PRs from `issue-{number}-*` branches. A message shows how many were hidden.
|
|
192
|
+
|
|
193
|
+
### PR Status Display
|
|
194
|
+
When cleaning, the tool shows the status of each worktree:
|
|
195
|
+
- `โ PR merged` - Safe to clean
|
|
196
|
+
- `โ PR open` - PR still under review
|
|
197
|
+
- `โ PR closed` - PR was closed without merging
|
|
198
|
+
- `โ Issue closed` - Issue was closed
|
|
199
|
+
- `โ Issue open` - Issue still open
|
|
200
|
+
|
|
201
|
+
### Orphaned Folder Cleanup
|
|
202
|
+
If a worktree folder exists but isn't registered in git (e.g., after a failed cleanup), the tool detects it and offers to remove it.
|
|
203
|
+
|
|
204
|
+
### Auto-Close Windows (macOS)
|
|
205
|
+
When cleaning a worktree, the tool automatically closes related terminal windows (iTerm2/Terminal.app) and VS Code windows that have the worktree open.
|
|
206
|
+
|
|
207
|
+
### Monorepo Support
|
|
208
|
+
The tool recursively finds and copies all `.env*` files from your project, preserving directory structure. This works great with turborepo and other monorepo setups where env files exist in subdirectories like `apps/myapp/.env.local`.
|
|
209
|
+
|
|
210
|
+
Skipped directories: `node_modules`, `.git`, `dist`, `build`, `.next`, `.turbo`
|
|
211
|
+
|
|
212
|
+
### Branch Naming
|
|
213
|
+
Branches are named `issue-{number}-{slug}` where the slug is:
|
|
214
|
+
- Lowercase with hyphens
|
|
215
|
+
- Max 30 characters
|
|
216
|
+
- Bracket prefixes removed (e.g., `[Bug]` is stripped)
|
|
217
|
+
- Duplicate consecutive words removed (e.g., `fix-fix-bug` โ `fix-bug`)
|
|
218
|
+
|
|
156
219
|
## Tips
|
|
157
220
|
|
|
158
|
-
-
|
|
159
|
-
-
|
|
160
|
-
-
|
|
161
|
-
- You can work on multiple issues in parallel - each gets its own worktree
|
|
221
|
+
- PRs are created automatically when Claude makes commits - no need to wait until the end
|
|
222
|
+
- Use `claude-issue clean --merged` after merging PRs for quick cleanup
|
|
223
|
+
- Worktrees share the same `.git` so commits are visible in the main repo
|
|
224
|
+
- You can work on multiple issues in parallel - each gets its own worktree and terminal
|
|
162
225
|
- Use `claude-issue go` to quickly navigate to worktrees or open PRs in browser
|
|
226
|
+
- The `go` command also offers options to open in Finder (macOS) or copy the cd command
|
|
227
|
+
|
|
228
|
+
## Platform Support
|
|
229
|
+
|
|
230
|
+
| Feature | macOS | Linux |
|
|
231
|
+
|---------|-------|-------|
|
|
232
|
+
| New terminal window | iTerm2, Terminal.app | gnome-terminal, xterm, konsole |
|
|
233
|
+
| Auto-close terminals on clean | โ | - |
|
|
234
|
+
| Auto-close VS Code on clean | โ | - |
|
|
235
|
+
| Open in Finder | โ | - |
|
|
163
236
|
|
|
164
237
|
## License
|
|
165
238
|
|
|
@@ -0,0 +1,23 @@
|
|
|
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.newCommand = newCommand;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const github_1 = require("../utils/github");
|
|
10
|
+
const solve_1 = require("./solve");
|
|
11
|
+
async function newCommand(title, options) {
|
|
12
|
+
const spinner = (0, ora_1.default)('Creating issue...').start();
|
|
13
|
+
const issueNumber = (0, github_1.createIssue)(title, options.body, options.label);
|
|
14
|
+
if (!issueNumber) {
|
|
15
|
+
spinner.fail('Failed to create issue');
|
|
16
|
+
console.log(chalk_1.default.dim('Make sure you have write access to this repository.'));
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
spinner.succeed(`Created issue #${issueNumber}`);
|
|
20
|
+
console.log(chalk_1.default.dim(`Title: ${title}\n`));
|
|
21
|
+
// Now solve it immediately
|
|
22
|
+
await (0, solve_1.solveCommand)(issueNumber);
|
|
23
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ const pr_1 = require("./commands/pr");
|
|
|
14
14
|
const clean_1 = require("./commands/clean");
|
|
15
15
|
const select_1 = require("./commands/select");
|
|
16
16
|
const go_1 = require("./commands/go");
|
|
17
|
+
const new_1 = require("./commands/new");
|
|
17
18
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
18
19
|
const packageJson = require('../package.json');
|
|
19
20
|
const program = new commander_1.Command();
|
|
@@ -110,4 +111,13 @@ program
|
|
|
110
111
|
}
|
|
111
112
|
await (0, go_1.goCommand)(issueNumber);
|
|
112
113
|
});
|
|
114
|
+
// New command - create issue and solve it
|
|
115
|
+
program
|
|
116
|
+
.command('new <title>')
|
|
117
|
+
.description('Create a new issue and immediately start solving it')
|
|
118
|
+
.option('-b, --body <body>', 'Issue description')
|
|
119
|
+
.option('-l, --label <label...>', 'Add labels to the issue')
|
|
120
|
+
.action(async (title, options) => {
|
|
121
|
+
await (0, new_1.newCommand)(title, options);
|
|
122
|
+
});
|
|
113
123
|
program.parse();
|
package/dist/utils/github.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export interface IssueListItem {
|
|
|
8
8
|
number: number;
|
|
9
9
|
title: string;
|
|
10
10
|
}
|
|
11
|
+
export declare function createIssue(title: string, body?: string, labels?: string[]): number | null;
|
|
11
12
|
export declare function getIssue(issueNumber: number): Issue | null;
|
|
12
13
|
export declare function listIssues(limit?: number): IssueListItem[];
|
|
13
14
|
export declare function createPullRequest(title: string, body: string, branch: string, base?: string): string;
|
package/dist/utils/github.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createIssue = createIssue;
|
|
3
4
|
exports.getIssue = getIssue;
|
|
4
5
|
exports.listIssues = listIssues;
|
|
5
6
|
exports.createPullRequest = createPullRequest;
|
|
@@ -7,6 +8,29 @@ exports.getIssueStatus = getIssueStatus;
|
|
|
7
8
|
exports.getPRForBranch = getPRForBranch;
|
|
8
9
|
exports.getIssuesWithOpenPRs = getIssuesWithOpenPRs;
|
|
9
10
|
const child_process_1 = require("child_process");
|
|
11
|
+
function createIssue(title, body, labels) {
|
|
12
|
+
try {
|
|
13
|
+
let cmd = `gh issue create --title "${title.replace(/"/g, '\\"')}"`;
|
|
14
|
+
if (body) {
|
|
15
|
+
cmd += ` --body "${body.replace(/"/g, '\\"')}"`;
|
|
16
|
+
}
|
|
17
|
+
if (labels && labels.length > 0) {
|
|
18
|
+
for (const label of labels) {
|
|
19
|
+
cmd += ` --label "${label.replace(/"/g, '\\"')}"`;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const output = (0, child_process_1.execSync)(cmd, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
|
|
23
|
+
// Output is the issue URL, extract the number
|
|
24
|
+
const match = output.trim().match(/\/issues\/(\d+)$/);
|
|
25
|
+
if (match) {
|
|
26
|
+
return parseInt(match[1], 10);
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
10
34
|
function getIssue(issueNumber) {
|
|
11
35
|
try {
|
|
12
36
|
const output = (0, child_process_1.execSync)(`gh issue view ${issueNumber} --json title,body,url`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
|