claude-issue-solver 1.10.0 โ†’ 1.11.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/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,12 +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)
49
50
  - โœจ **Create and solve** - Create new issues and start solving them immediately
50
51
  - ๐ŸŒฟ **Worktree isolation** - Each issue gets its own worktree, work on multiple issues in parallel
51
- - ๐Ÿค– **Automatic PR creation** - Creates a PR that closes the issue when merged
52
- - ๐Ÿ“ **Works with any repo** - Auto-detects project name from git remote
53
- - ๐Ÿ’ป **Opens in new terminal** - Keeps your current terminal free (supports iTerm2 and Terminal.app on macOS)
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)
54
56
 
55
57
  ## Requirements
56
58
 
@@ -65,6 +67,17 @@ Open issues for my-project:
65
67
  npm install -g claude-issue-solver
66
68
  ```
67
69
 
70
+ Then run the setup wizard to check/install requirements:
71
+
72
+ ```bash
73
+ claude-issue init
74
+ ```
75
+
76
+ This will:
77
+ - Check for Node.js, GitHub CLI, Claude Code, and Git
78
+ - Install missing tools (on macOS via Homebrew)
79
+ - Guide you through authentication for `gh` and `claude`
80
+
68
81
  Or install from source:
69
82
 
70
83
  ```bash
@@ -88,37 +101,61 @@ claude-issue 42
88
101
 
89
102
  # List open issues
90
103
  claude-issue list
104
+ claude-issue ls
105
+
106
+ # Create a new issue and solve it immediately
107
+ claude-issue new "Add dark mode support"
108
+ claude-issue new "Fix login bug" -b "Users can't login on mobile"
109
+ claude-issue new "Fix crash" -l bug -l priority
91
110
 
92
111
  # Create PR for a solved issue (if you skipped it earlier)
93
112
  claude-issue pr 42
94
113
 
95
- # Clean up worktree and branch after PR is merged
96
- claude-issue clean 42
97
-
98
- # Clean all worktrees (shows PR/issue status)
99
- claude-issue clean
114
+ # Clean up worktree and branch
115
+ claude-issue clean 42 # Clean specific issue
116
+ claude-issue clean # Interactive selection
117
+ claude-issue clean --all # Clean all worktrees (with confirmation)
118
+ claude-issue clean --merged # Auto-clean only merged PRs (no confirmation)
100
119
 
101
120
  # Navigate to a worktree or open its PR
102
- claude-issue go
103
-
104
- # Create a new issue and solve it immediately
105
- claude-issue new "Add dark mode support"
106
-
107
- # With description and labels
108
- claude-issue new "Fix login bug" -b "Users can't login on mobile" -l bug
121
+ claude-issue go # Interactive selection
122
+ claude-issue go 42 # Go to specific issue
109
123
 
110
124
  # Show help
111
125
  claude-issue --help
112
126
  ```
113
127
 
128
+ ## Commands Reference
129
+
130
+ | Command | Alias | Description |
131
+ |---------|-------|-------------|
132
+ | `claude-issue` | - | Interactive issue selection |
133
+ | `claude-issue <number>` | - | Solve specific issue |
134
+ | `claude-issue new <title>` | - | Create issue and solve it |
135
+ | `claude-issue list` | `ls` | List open issues |
136
+ | `claude-issue pr <number>` | - | Create PR for solved issue |
137
+ | `claude-issue clean [number]` | `rm` | Remove worktree and branch |
138
+ | `claude-issue go [number]` | - | Navigate to worktree |
139
+ | `claude-issue init` | - | Setup wizard for requirements |
140
+
141
+ ### Command Options
142
+
143
+ **`new` command:**
144
+ - `-b, --body <text>` - Issue description
145
+ - `-l, --label <name>` - Add label (can be used multiple times)
146
+
147
+ **`clean` command:**
148
+ - `-a, --all` - Clean all issue worktrees (with confirmation)
149
+ - `-m, --merged` - Clean only worktrees with merged PRs (no confirmation)
150
+
114
151
  ## How it works
115
152
 
116
153
  1. **Fetches issue** - Gets title and description from GitHub
117
154
  2. **Creates worktree** - Makes a new git worktree with branch `issue-{number}-{slug}`
118
- 3. **Sets up environment** - Copies `.env` files, symlinks `node_modules`
155
+ 3. **Sets up environment** - Recursively copies all `.env*` files, symlinks `node_modules`
119
156
  4. **Opens Claude** - Launches Claude Code in a new terminal with the issue as context
120
- 5. **Interactive session** - Claude stays open so you can ask for changes
121
- 6. **Creates PR** - When you exit, prompts to create a PR that closes the issue
157
+ 5. **Real-time PR creation** - Background watcher creates PR on first commit, pushes updates on subsequent commits
158
+ 6. **Interactive session** - Claude stays open so you can ask for changes
122
159
 
123
160
  ## Workflow
124
161
 
@@ -149,24 +186,65 @@ claude-issue --help
149
186
  โ”‚
150
187
  โ–ผ
151
188
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
152
- โ”‚ Create PR โ”‚
189
+ โ”‚ Auto-create PR โ”‚
153
190
  โ”‚ "Closes #42" โ”‚
154
191
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
155
192
  โ”‚
156
193
  โ–ผ
157
194
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
158
195
  โ”‚ claude-issue โ”‚
159
- โ”‚ clean 42 โ”‚
196
+ โ”‚ clean --merged โ”‚
160
197
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
161
198
  ```
162
199
 
200
+ ## Smart Features
201
+
202
+ ### Issue Filtering
203
+ When selecting issues, the tool automatically hides issues that already have open PRs from `issue-{number}-*` branches. A message shows how many were hidden.
204
+
205
+ ### PR Status Display
206
+ When cleaning, the tool shows the status of each worktree:
207
+ - `โœ“ PR merged` - Safe to clean
208
+ - `โ— PR open` - PR still under review
209
+ - `โœ— PR closed` - PR was closed without merging
210
+ - `โ— Issue closed` - Issue was closed
211
+ - `โ—‹ Issue open` - Issue still open
212
+
213
+ ### Orphaned Folder Cleanup
214
+ 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.
215
+
216
+ ### Auto-Close Windows (macOS)
217
+ When cleaning a worktree, the tool automatically closes related terminal windows (iTerm2/Terminal.app) and VS Code windows that have the worktree open.
218
+
219
+ ### Monorepo Support
220
+ 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`.
221
+
222
+ Skipped directories: `node_modules`, `.git`, `dist`, `build`, `.next`, `.turbo`
223
+
224
+ ### Branch Naming
225
+ Branches are named `issue-{number}-{slug}` where the slug is:
226
+ - Lowercase with hyphens
227
+ - Max 30 characters
228
+ - Bracket prefixes removed (e.g., `[Bug]` is stripped)
229
+ - Duplicate consecutive words removed (e.g., `fix-fix-bug` โ†’ `fix-bug`)
230
+
163
231
  ## Tips
164
232
 
165
- - Use `/exit` in Claude to end the session and trigger PR creation
166
- - Worktrees share the same `.git` so commits are visible in main repo
167
- - Run `claude-issue clean` after merging to clean up - it shows PR status (merged/open/closed)
168
- - You can work on multiple issues in parallel - each gets its own worktree
233
+ - PRs are created automatically when Claude makes commits - no need to wait until the end
234
+ - Use `claude-issue clean --merged` after merging PRs for quick cleanup
235
+ - Worktrees share the same `.git` so commits are visible in the main repo
236
+ - You can work on multiple issues in parallel - each gets its own worktree and terminal
169
237
  - Use `claude-issue go` to quickly navigate to worktrees or open PRs in browser
238
+ - The `go` command also offers options to open in Finder (macOS) or copy the cd command
239
+
240
+ ## Platform Support
241
+
242
+ | Feature | macOS | Linux |
243
+ |---------|-------|-------|
244
+ | New terminal window | iTerm2, Terminal.app | gnome-terminal, xterm, konsole |
245
+ | Auto-close terminals on clean | โœ“ | - |
246
+ | Auto-close VS Code on clean | โœ“ | - |
247
+ | Open in Finder | โœ“ | - |
170
248
 
171
249
  ## License
172
250
 
@@ -0,0 +1 @@
1
+ export declare function initCommand(): Promise<void>;
@@ -0,0 +1,232 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.initCommand = initCommand;
40
+ const chalk_1 = __importDefault(require("chalk"));
41
+ const ora_1 = __importDefault(require("ora"));
42
+ const child_process_1 = require("child_process");
43
+ const os = __importStar(require("os"));
44
+ function commandExists(cmd) {
45
+ try {
46
+ (0, child_process_1.execSync)(`which ${cmd}`, { stdio: 'pipe' });
47
+ return true;
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ }
53
+ function isGhAuthenticated() {
54
+ try {
55
+ (0, child_process_1.execSync)('gh auth status', { stdio: 'pipe' });
56
+ return true;
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ }
62
+ function isClaudeAuthenticated() {
63
+ try {
64
+ // Claude Code stores auth in ~/.claude or similar
65
+ // Just check if it runs without error
66
+ (0, child_process_1.execSync)('claude --version', { stdio: 'pipe' });
67
+ return true;
68
+ }
69
+ catch {
70
+ return false;
71
+ }
72
+ }
73
+ function installWithBrew(pkg) {
74
+ if (!commandExists('brew')) {
75
+ console.log(chalk_1.default.yellow(`\n Homebrew not found. Please install ${pkg} manually.`));
76
+ return false;
77
+ }
78
+ try {
79
+ console.log(chalk_1.default.dim(`\n Running: brew install ${pkg}`));
80
+ (0, child_process_1.spawnSync)('brew', ['install', pkg], { stdio: 'inherit' });
81
+ return commandExists(pkg === 'gh' ? 'gh' : pkg);
82
+ }
83
+ catch {
84
+ return false;
85
+ }
86
+ }
87
+ function installWithNpm(pkg) {
88
+ try {
89
+ console.log(chalk_1.default.dim(`\n Running: npm install -g ${pkg}`));
90
+ (0, child_process_1.spawnSync)('npm', ['install', '-g', pkg], { stdio: 'inherit' });
91
+ return true;
92
+ }
93
+ catch {
94
+ return false;
95
+ }
96
+ }
97
+ function runGhAuth() {
98
+ try {
99
+ console.log(chalk_1.default.dim('\n Running: gh auth login'));
100
+ console.log(chalk_1.default.cyan(' Follow the prompts to authenticate with GitHub:\n'));
101
+ (0, child_process_1.spawnSync)('gh', ['auth', 'login'], { stdio: 'inherit' });
102
+ return isGhAuthenticated();
103
+ }
104
+ catch {
105
+ return false;
106
+ }
107
+ }
108
+ function runClaudeAuth() {
109
+ try {
110
+ console.log(chalk_1.default.dim('\n Running: claude'));
111
+ console.log(chalk_1.default.cyan(' Follow the prompts to authenticate with Anthropic:\n'));
112
+ (0, child_process_1.spawnSync)('claude', ['--help'], { stdio: 'inherit' });
113
+ return true;
114
+ }
115
+ catch {
116
+ return false;
117
+ }
118
+ }
119
+ async function initCommand() {
120
+ console.log(chalk_1.default.bold('\n๐Ÿ”ง Claude Issue Solver - Setup\n'));
121
+ const platform = os.platform();
122
+ const isMac = platform === 'darwin';
123
+ const requirements = [
124
+ {
125
+ name: 'Node.js',
126
+ check: () => {
127
+ try {
128
+ const version = (0, child_process_1.execSync)('node --version', { encoding: 'utf-8' }).trim();
129
+ const major = parseInt(version.replace('v', '').split('.')[0], 10);
130
+ return major >= 18;
131
+ }
132
+ catch {
133
+ return false;
134
+ }
135
+ },
136
+ installCmd: 'https://nodejs.org/ or: brew install node',
137
+ },
138
+ {
139
+ name: 'GitHub CLI',
140
+ check: () => commandExists('gh'),
141
+ install: () => installWithBrew('gh'),
142
+ authCheck: isGhAuthenticated,
143
+ auth: runGhAuth,
144
+ installCmd: isMac ? 'brew install gh' : 'https://cli.github.com/',
145
+ authCmd: 'gh auth login',
146
+ },
147
+ {
148
+ name: 'Claude Code',
149
+ check: () => commandExists('claude'),
150
+ install: () => installWithNpm('@anthropic-ai/claude-code'),
151
+ authCheck: isClaudeAuthenticated,
152
+ auth: runClaudeAuth,
153
+ installCmd: 'npm install -g @anthropic-ai/claude-code',
154
+ authCmd: 'claude (follow prompts)',
155
+ },
156
+ {
157
+ name: 'Git',
158
+ check: () => commandExists('git'),
159
+ installCmd: isMac ? 'xcode-select --install' : 'apt install git',
160
+ },
161
+ ];
162
+ let allPassed = true;
163
+ for (const req of requirements) {
164
+ const spinner = (0, ora_1.default)(`Checking ${req.name}...`).start();
165
+ // Check if installed
166
+ if (req.check()) {
167
+ // Check if authenticated (if applicable)
168
+ if (req.authCheck && !req.authCheck()) {
169
+ spinner.warn(chalk_1.default.yellow(`${req.name} - not authenticated`));
170
+ if (req.auth) {
171
+ const authSpinner = (0, ora_1.default)(`Authenticating ${req.name}...`).start();
172
+ authSpinner.stop();
173
+ if (req.auth()) {
174
+ console.log(chalk_1.default.green(` โœ“ ${req.name} authenticated`));
175
+ }
176
+ else {
177
+ console.log(chalk_1.default.red(` โœ— ${req.name} authentication failed`));
178
+ console.log(chalk_1.default.dim(` Run manually: ${req.authCmd}`));
179
+ allPassed = false;
180
+ }
181
+ }
182
+ }
183
+ else {
184
+ spinner.succeed(chalk_1.default.green(`${req.name}`));
185
+ }
186
+ }
187
+ else {
188
+ spinner.fail(chalk_1.default.red(`${req.name} - not found`));
189
+ // Try to install
190
+ if (req.install && isMac) {
191
+ const installSpinner = (0, ora_1.default)(`Installing ${req.name}...`).start();
192
+ installSpinner.stop();
193
+ if (req.install()) {
194
+ console.log(chalk_1.default.green(` โœ“ ${req.name} installed`));
195
+ // Now check auth if needed
196
+ if (req.authCheck && !req.authCheck() && req.auth) {
197
+ console.log(chalk_1.default.yellow(` โ†’ ${req.name} needs authentication`));
198
+ if (req.auth()) {
199
+ console.log(chalk_1.default.green(` โœ“ ${req.name} authenticated`));
200
+ }
201
+ else {
202
+ console.log(chalk_1.default.red(` โœ— ${req.name} authentication failed`));
203
+ console.log(chalk_1.default.dim(` Run manually: ${req.authCmd}`));
204
+ allPassed = false;
205
+ }
206
+ }
207
+ }
208
+ else {
209
+ console.log(chalk_1.default.red(` โœ— Failed to install ${req.name}`));
210
+ console.log(chalk_1.default.dim(` Install manually: ${req.installCmd}`));
211
+ allPassed = false;
212
+ }
213
+ }
214
+ else {
215
+ console.log(chalk_1.default.dim(` Install: ${req.installCmd}`));
216
+ allPassed = false;
217
+ }
218
+ }
219
+ }
220
+ console.log();
221
+ if (allPassed) {
222
+ console.log(chalk_1.default.green.bold('โœ… All requirements met! You\'re ready to use claude-issue.\n'));
223
+ console.log(chalk_1.default.dim('Try running:'));
224
+ console.log(chalk_1.default.cyan(' claude-issue list # List open issues'));
225
+ console.log(chalk_1.default.cyan(' claude-issue # Interactive issue selection'));
226
+ console.log(chalk_1.default.cyan(' claude-issue new "Title" # Create and solve new issue\n'));
227
+ }
228
+ else {
229
+ console.log(chalk_1.default.yellow.bold('โš ๏ธ Some requirements are missing.\n'));
230
+ console.log(chalk_1.default.dim('Please install the missing requirements and run `claude-issue init` again.\n'));
231
+ }
232
+ }
package/dist/index.js CHANGED
@@ -15,6 +15,7 @@ const clean_1 = require("./commands/clean");
15
15
  const select_1 = require("./commands/select");
16
16
  const go_1 = require("./commands/go");
17
17
  const new_1 = require("./commands/new");
18
+ const init_1 = require("./commands/init");
18
19
  // eslint-disable-next-line @typescript-eslint/no-var-requires
19
20
  const packageJson = require('../package.json');
20
21
  const program = new commander_1.Command();
@@ -22,8 +23,14 @@ program
22
23
  .name('claude-issue')
23
24
  .description('Automatically solve GitHub issues using Claude Code')
24
25
  .version(packageJson.version);
25
- // Check requirements before any command
26
- program.hook('preAction', () => {
26
+ // Commands that skip requirements check
27
+ const skipRequirementsCommands = ['init'];
28
+ // Check requirements before any command (except init)
29
+ program.hook('preAction', (thisCommand) => {
30
+ const commandName = thisCommand.name();
31
+ if (skipRequirementsCommands.includes(commandName)) {
32
+ return;
33
+ }
27
34
  if (!(0, git_1.isGitRepo)()) {
28
35
  console.log(chalk_1.default.red('โŒ Not in a git repository'));
29
36
  process.exit(1);
@@ -120,4 +127,11 @@ program
120
127
  .action(async (title, options) => {
121
128
  await (0, new_1.newCommand)(title, options);
122
129
  });
130
+ // Init command - guided setup
131
+ program
132
+ .command('init')
133
+ .description('Check and install requirements (gh, claude-code)')
134
+ .action(async () => {
135
+ await (0, init_1.initCommand)();
136
+ });
123
137
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-issue-solver",
3
- "version": "1.10.0",
3
+ "version": "1.11.0",
4
4
  "description": "Automatically solve GitHub issues using Claude Code",
5
5
  "main": "dist/index.js",
6
6
  "bin": {