claude-issue-solver 1.8.3 → 1.10.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
@@ -46,6 +46,7 @@ Open issues for my-project:
46
46
  ## Features
47
47
 
48
48
  - 🎯 **Interactive issue selection** - Lists open issues with arrow-key navigation
49
+ - ✨ **Create and solve** - Create new issues and start solving them immediately
49
50
  - 🌿 **Worktree isolation** - Each issue gets its own worktree, work on multiple issues in parallel
50
51
  - 🤖 **Automatic PR creation** - Creates a PR that closes the issue when merged
51
52
  - 📁 **Works with any repo** - Auto-detects project name from git remote
@@ -100,6 +101,12 @@ claude-issue clean
100
101
  # Navigate to a worktree or open its PR
101
102
  claude-issue go
102
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
109
+
103
110
  # Show help
104
111
  claude-issue --help
105
112
  ```
@@ -0,0 +1,4 @@
1
+ export declare function newCommand(title: string, options: {
2
+ body?: string;
3
+ label?: string[];
4
+ }): Promise<void>;
@@ -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
+ }
@@ -17,7 +17,19 @@ async function selectCommand() {
17
17
  console.log(chalk_1.default.yellow('No open issues found.'));
18
18
  return;
19
19
  }
20
- const choices = issues.map((issue) => ({
20
+ // Filter out issues that already have open PRs
21
+ const issuesWithPRs = (0, github_1.getIssuesWithOpenPRs)();
22
+ const availableIssues = issues.filter((issue) => !issuesWithPRs.has(issue.number));
23
+ if (availableIssues.length === 0) {
24
+ console.log(chalk_1.default.yellow('All open issues already have PRs in progress.'));
25
+ console.log(chalk_1.default.dim('Use `claude-issue go` to navigate to existing worktrees.'));
26
+ return;
27
+ }
28
+ if (issuesWithPRs.size > 0) {
29
+ const skipped = issues.length - availableIssues.length;
30
+ console.log(chalk_1.default.dim(`(${skipped} issue${skipped > 1 ? 's' : ''} with open PRs hidden)\n`));
31
+ }
32
+ const choices = availableIssues.map((issue) => ({
21
33
  name: `#${issue.number}\t${issue.title}`,
22
34
  value: issue.number,
23
35
  }));
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();
@@ -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;
@@ -20,3 +21,8 @@ export interface PRStatus {
20
21
  }
21
22
  export declare function getIssueStatus(issueNumber: number): IssueStatus | null;
22
23
  export declare function getPRForBranch(branch: string): PRStatus | null;
24
+ /**
25
+ * Get all open PRs with their head branch names (single API call)
26
+ * Returns a Set of issue numbers that have open PRs from issue-{number}-* branches
27
+ */
28
+ export declare function getIssuesWithOpenPRs(): Set<number>;
@@ -1,11 +1,36 @@
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;
6
7
  exports.getIssueStatus = getIssueStatus;
7
8
  exports.getPRForBranch = getPRForBranch;
9
+ exports.getIssuesWithOpenPRs = getIssuesWithOpenPRs;
8
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
+ }
9
34
  function getIssue(issueNumber) {
10
35
  try {
11
36
  const output = (0, child_process_1.execSync)(`gh issue view ${issueNumber} --json title,body,url`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
@@ -61,3 +86,25 @@ function getPRForBranch(branch) {
61
86
  return null;
62
87
  }
63
88
  }
89
+ /**
90
+ * Get all open PRs with their head branch names (single API call)
91
+ * Returns a Set of issue numbers that have open PRs from issue-{number}-* branches
92
+ */
93
+ function getIssuesWithOpenPRs() {
94
+ try {
95
+ const output = (0, child_process_1.execSync)(`gh pr list --state open --json headRefName --limit 100`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
96
+ const data = JSON.parse(output);
97
+ const issueNumbers = new Set();
98
+ for (const pr of data) {
99
+ // Match branches like "issue-42-fix-bug"
100
+ const match = pr.headRefName.match(/^issue-(\d+)-/);
101
+ if (match) {
102
+ issueNumbers.add(parseInt(match[1], 10));
103
+ }
104
+ }
105
+ return issueNumbers;
106
+ }
107
+ catch {
108
+ return new Set();
109
+ }
110
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-issue-solver",
3
- "version": "1.8.3",
3
+ "version": "1.10.0",
4
4
  "description": "Automatically solve GitHub issues using Claude Code",
5
5
  "main": "dist/index.js",
6
6
  "bin": {