claude-queue 1.4.0 → 1.5.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 +61 -4
- package/claude-queue.sh +435 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# claude-queue
|
|
2
2
|
|
|
3
|
-
Automated GitHub issue solver.
|
|
3
|
+
Automated GitHub issue solver & creator. Create well-structured issues from a text dump or interactive interview, then let Claude Code solve them overnight.
|
|
4
4
|
|
|
5
|
-
claude-queue
|
|
5
|
+
claude-queue has two modes:
|
|
6
|
+
- **Solve** (default) — fetches open issues, uses [Claude Code](https://docs.anthropic.com/en/docs/claude-code) to solve each one, and opens a pull request
|
|
7
|
+
- **Create** — decomposes a description into well-structured GitHub issues, either from inline text or via an interactive interview
|
|
6
8
|
|
|
7
9
|
## Prerequisites
|
|
8
10
|
|
|
@@ -24,13 +26,15 @@ npx claude-queue
|
|
|
24
26
|
|
|
25
27
|
## Usage
|
|
26
28
|
|
|
29
|
+
### Solving issues
|
|
30
|
+
|
|
27
31
|
Run from inside any git repository with GitHub issues:
|
|
28
32
|
|
|
29
33
|
```bash
|
|
30
34
|
claude-queue
|
|
31
35
|
```
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
#### Solve options
|
|
34
38
|
|
|
35
39
|
| Flag | Default | Description |
|
|
36
40
|
|------|---------|-------------|
|
|
@@ -40,7 +44,7 @@ claude-queue
|
|
|
40
44
|
| `--model MODEL` | CLI default | Claude model to use (e.g. `claude-sonnet-4-5-20250929`) |
|
|
41
45
|
| `-h, --help` | | Show help |
|
|
42
46
|
|
|
43
|
-
|
|
47
|
+
#### Solve examples
|
|
44
48
|
|
|
45
49
|
```bash
|
|
46
50
|
# Solve all open issues
|
|
@@ -53,6 +57,59 @@ claude-queue --label bug
|
|
|
53
57
|
claude-queue --max-retries 5 --model claude-sonnet-4-5-20250929
|
|
54
58
|
```
|
|
55
59
|
|
|
60
|
+
### Creating issues
|
|
61
|
+
|
|
62
|
+
Generate well-structured GitHub issues from a text description or an interactive interview with Claude.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
claude-queue create "Add dark mode and fix the login bug"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
There are three ways to provide input:
|
|
69
|
+
|
|
70
|
+
1. **Inline text** — pass your description as an argument
|
|
71
|
+
2. **Stdin** — run `claude-queue create` with no arguments, type or paste your text, then press Ctrl+D
|
|
72
|
+
3. **Interactive** — run `claude-queue create -i` and Claude will ask clarifying questions before generating issues
|
|
73
|
+
|
|
74
|
+
In all modes, Claude decomposes the input into individual, actionable issues with titles, markdown bodies, and labels (reusing existing repo labels where possible). You get a preview before anything is created.
|
|
75
|
+
|
|
76
|
+
#### Create options
|
|
77
|
+
|
|
78
|
+
| Flag | Default | Description |
|
|
79
|
+
|------|---------|-------------|
|
|
80
|
+
| `-i, --interactive` | off | Interview mode — Claude asks clarifying questions first |
|
|
81
|
+
| `--label LABEL` | none | Add this label to every created issue |
|
|
82
|
+
| `--model MODEL` | CLI default | Claude model to use |
|
|
83
|
+
| `-h, --help` | | Show help for create |
|
|
84
|
+
|
|
85
|
+
#### Create examples
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Create issues from a text description
|
|
89
|
+
claude-queue create "Add user avatars, implement search, and fix the 404 on /settings"
|
|
90
|
+
|
|
91
|
+
# Interactive mode — Claude asks questions first
|
|
92
|
+
claude-queue create -i
|
|
93
|
+
|
|
94
|
+
# Paste a longer description via stdin
|
|
95
|
+
claude-queue create
|
|
96
|
+
|
|
97
|
+
# Add a label to all created issues (useful with --label on solve)
|
|
98
|
+
claude-queue create --label backlog "Refactor the auth module and add rate limiting"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Workflow: create then solve
|
|
102
|
+
|
|
103
|
+
The `--label` flag on both commands lets you create a workflow where `create` plans the issues and bare `claude-queue` solves them:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Plan: create issues tagged "nightshift"
|
|
107
|
+
claude-queue create --label nightshift "Add dark mode and fix the login bug"
|
|
108
|
+
|
|
109
|
+
# Solve: only process those issues
|
|
110
|
+
claude-queue --label nightshift
|
|
111
|
+
```
|
|
112
|
+
|
|
56
113
|
## Configuration
|
|
57
114
|
|
|
58
115
|
Create a `.claude-queue` file in your repo root to add custom instructions to every issue prompt:
|
package/claude-queue.sh
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
#
|
|
3
|
-
# claude-queue - Automated GitHub issue solver
|
|
3
|
+
# claude-queue - Automated GitHub issue solver & creator
|
|
4
4
|
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
5
|
+
# Commands:
|
|
6
|
+
# claude-queue [options] Solve open issues (default)
|
|
7
|
+
# claude-queue create [options] Create issues from text or interactively
|
|
7
8
|
#
|
|
8
|
-
#
|
|
9
|
-
# claude-queue [options]
|
|
10
|
-
#
|
|
11
|
-
# Options:
|
|
9
|
+
# Solve options:
|
|
12
10
|
# --max-retries N Max retries per issue (default: 3)
|
|
13
11
|
# --max-turns N Max Claude turns per attempt (default: 50)
|
|
14
12
|
# --label LABEL Only process issues with this label
|
|
15
13
|
# --model MODEL Claude model to use
|
|
16
14
|
# -v, --version Show version
|
|
17
15
|
# -h, --help Show this help message
|
|
16
|
+
#
|
|
17
|
+
# Create options:
|
|
18
|
+
# -i, --interactive Interview mode (Claude asks questions)
|
|
19
|
+
# --label LABEL Add this label to all created issues
|
|
20
|
+
# --model MODEL Claude model to use
|
|
21
|
+
# -h, --help Show help for create
|
|
18
22
|
|
|
19
23
|
set -euo pipefail
|
|
20
24
|
|
|
@@ -47,17 +51,38 @@ declare -a SKIPPED_ISSUES=()
|
|
|
47
51
|
CURRENT_ISSUE=""
|
|
48
52
|
START_TIME=$(date +%s)
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
show_help() {
|
|
55
|
+
echo "claude-queue v${VERSION} — Automated GitHub issue solver & creator"
|
|
56
|
+
echo ""
|
|
57
|
+
echo "Usage:"
|
|
58
|
+
echo " claude-queue [options] Solve open issues (default)"
|
|
59
|
+
echo " claude-queue create [options] [text] Create issues from text or interactively"
|
|
60
|
+
echo ""
|
|
61
|
+
echo "Solve options:"
|
|
62
|
+
echo " --max-retries N Max retries per issue (default: 3)"
|
|
63
|
+
echo " --max-turns N Max Claude turns per attempt (default: 50)"
|
|
64
|
+
echo " --label LABEL Only process issues with this label"
|
|
65
|
+
echo " --model MODEL Claude model to use"
|
|
66
|
+
echo " -v, --version Show version"
|
|
67
|
+
echo " -h, --help Show this help message"
|
|
68
|
+
echo ""
|
|
69
|
+
echo "Run 'claude-queue create --help' for create options."
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
show_create_help() {
|
|
73
|
+
echo "claude-queue create — Generate GitHub issues from text or an interactive interview"
|
|
74
|
+
echo ""
|
|
75
|
+
echo "Usage:"
|
|
76
|
+
echo " claude-queue create \"description\" Create issues from inline text"
|
|
77
|
+
echo " claude-queue create Prompt for text input (Ctrl+D to finish)"
|
|
78
|
+
echo " claude-queue create -i Interactive interview mode"
|
|
79
|
+
echo ""
|
|
80
|
+
echo "Options:"
|
|
81
|
+
echo " -i, --interactive Interview mode (Claude asks clarifying questions first)"
|
|
82
|
+
echo " --label LABEL Add this label to every created issue"
|
|
83
|
+
echo " --model MODEL Claude model to use"
|
|
84
|
+
echo " -h, --help Show this help message"
|
|
85
|
+
}
|
|
61
86
|
|
|
62
87
|
log() { echo -e "${DIM}$(date +%H:%M:%S)${NC} ${BLUE}[claude-queue]${NC} $1"; }
|
|
63
88
|
log_success() { echo -e "${DIM}$(date +%H:%M:%S)${NC} ${GREEN}[claude-queue]${NC} $1"; }
|
|
@@ -79,7 +104,9 @@ cleanup() {
|
|
|
79
104
|
log_warn "Branch '${BRANCH}' has your commits. Push manually if needed."
|
|
80
105
|
fi
|
|
81
106
|
|
|
82
|
-
|
|
107
|
+
if [ -d "$LOG_DIR" ]; then
|
|
108
|
+
log "Logs saved to: ${LOG_DIR}"
|
|
109
|
+
fi
|
|
83
110
|
}
|
|
84
111
|
trap cleanup EXIT
|
|
85
112
|
|
|
@@ -536,4 +563,392 @@ main() {
|
|
|
536
563
|
log "Logs: ${LOG_DIR}"
|
|
537
564
|
}
|
|
538
565
|
|
|
539
|
-
|
|
566
|
+
create_preflight() {
|
|
567
|
+
log_header "Preflight Checks"
|
|
568
|
+
|
|
569
|
+
local failed=false
|
|
570
|
+
|
|
571
|
+
for cmd in gh claude jq; do
|
|
572
|
+
if command -v "$cmd" &>/dev/null; then
|
|
573
|
+
log " $cmd ... found"
|
|
574
|
+
else
|
|
575
|
+
log_error " $cmd ... NOT FOUND"
|
|
576
|
+
failed=true
|
|
577
|
+
fi
|
|
578
|
+
done
|
|
579
|
+
|
|
580
|
+
if ! gh auth status &>/dev/null; then
|
|
581
|
+
log_error " gh auth ... not authenticated"
|
|
582
|
+
failed=true
|
|
583
|
+
else
|
|
584
|
+
log " gh auth ... ok"
|
|
585
|
+
fi
|
|
586
|
+
|
|
587
|
+
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
|
|
588
|
+
log_error " git repo ... not inside a git repository"
|
|
589
|
+
failed=true
|
|
590
|
+
else
|
|
591
|
+
log " git repo ... ok"
|
|
592
|
+
fi
|
|
593
|
+
|
|
594
|
+
if [ "$failed" = true ]; then
|
|
595
|
+
log_error "Preflight failed. Aborting."
|
|
596
|
+
exit 1
|
|
597
|
+
fi
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
get_repo_labels() {
|
|
601
|
+
gh label list --json name -q '.[].name' 2>/dev/null | paste -sd ',' -
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
extract_json() {
|
|
605
|
+
local input="$1"
|
|
606
|
+
local json
|
|
607
|
+
|
|
608
|
+
json=$(echo "$input" | sed -n '/^```\(json\)\?$/,/^```$/{ /^```/d; p; }')
|
|
609
|
+
if [ -z "$json" ]; then
|
|
610
|
+
json="$input"
|
|
611
|
+
fi
|
|
612
|
+
|
|
613
|
+
if echo "$json" | jq empty 2>/dev/null; then
|
|
614
|
+
echo "$json"
|
|
615
|
+
return 0
|
|
616
|
+
fi
|
|
617
|
+
|
|
618
|
+
json=$(echo "$input" | grep -o '\[.*\]' | head -1)
|
|
619
|
+
if [ -n "$json" ] && echo "$json" | jq empty 2>/dev/null; then
|
|
620
|
+
echo "$json"
|
|
621
|
+
return 0
|
|
622
|
+
fi
|
|
623
|
+
|
|
624
|
+
return 1
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
create_from_text() {
|
|
628
|
+
local user_text="$1"
|
|
629
|
+
local repo_labels
|
|
630
|
+
repo_labels=$(get_repo_labels)
|
|
631
|
+
|
|
632
|
+
log "Analyzing text and generating issues..."
|
|
633
|
+
|
|
634
|
+
local prompt
|
|
635
|
+
prompt="You are a GitHub issue planner. The user wants to create issues for a repository.
|
|
636
|
+
|
|
637
|
+
Existing labels in the repo: ${repo_labels}
|
|
638
|
+
|
|
639
|
+
The user's description:
|
|
640
|
+
${user_text}
|
|
641
|
+
|
|
642
|
+
Decompose this into a JSON array of well-structured GitHub issues. Each issue should have:
|
|
643
|
+
- \"title\": a clear, concise issue title
|
|
644
|
+
- \"body\": a detailed issue body in markdown (include acceptance criteria where appropriate)
|
|
645
|
+
- \"labels\": an array of label strings (reuse existing repo labels when they fit, or suggest new ones)
|
|
646
|
+
|
|
647
|
+
Rules:
|
|
648
|
+
- Create separate issues for logically distinct tasks
|
|
649
|
+
- Each issue should be independently actionable
|
|
650
|
+
- Use clear, imperative titles (e.g. \"Add dark mode toggle to settings page\")
|
|
651
|
+
- If the description is vague, make reasonable assumptions and note them in the body
|
|
652
|
+
|
|
653
|
+
Output ONLY the JSON array, no other text."
|
|
654
|
+
|
|
655
|
+
local output
|
|
656
|
+
# shellcheck disable=SC2086
|
|
657
|
+
output=$(claude -p "$prompt" $MODEL_FLAG 2>/dev/null)
|
|
658
|
+
|
|
659
|
+
local json
|
|
660
|
+
if ! json=$(extract_json "$output"); then
|
|
661
|
+
log_error "Failed to parse Claude's response as JSON"
|
|
662
|
+
log_error "Raw output:"
|
|
663
|
+
echo "$output"
|
|
664
|
+
exit 1
|
|
665
|
+
fi
|
|
666
|
+
|
|
667
|
+
local count
|
|
668
|
+
count=$(echo "$json" | jq length)
|
|
669
|
+
if [ "$count" -eq 0 ]; then
|
|
670
|
+
log_error "No issues were generated"
|
|
671
|
+
exit 1
|
|
672
|
+
fi
|
|
673
|
+
|
|
674
|
+
echo "$json"
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
create_interactive() {
|
|
678
|
+
local repo_labels
|
|
679
|
+
repo_labels=$(get_repo_labels)
|
|
680
|
+
local conversation=""
|
|
681
|
+
local max_turns=10
|
|
682
|
+
local turn=0
|
|
683
|
+
|
|
684
|
+
local system_prompt="You are a GitHub issue planner conducting an interview to understand what issues to create for a repository.
|
|
685
|
+
|
|
686
|
+
Existing labels in the repo: ${repo_labels}
|
|
687
|
+
|
|
688
|
+
Your job:
|
|
689
|
+
1. Ask focused questions to understand what the user wants to build or fix
|
|
690
|
+
2. Ask about priorities, scope, and acceptance criteria
|
|
691
|
+
3. When you have enough information, output the marker CLAUDE_QUEUE_READY on its own line, followed by a JSON array of issues
|
|
692
|
+
|
|
693
|
+
Each issue in the JSON array should have:
|
|
694
|
+
- \"title\": a clear, concise issue title
|
|
695
|
+
- \"body\": a detailed issue body in markdown
|
|
696
|
+
- \"labels\": an array of label strings (reuse existing repo labels when they fit)
|
|
697
|
+
|
|
698
|
+
Rules:
|
|
699
|
+
- Ask one question at a time
|
|
700
|
+
- Keep questions short and specific
|
|
701
|
+
- After 2-3 questions you should have enough context — don't over-interview
|
|
702
|
+
- If the user says \"done\", immediately generate the issues with what you know
|
|
703
|
+
- Output ONLY your question text (no JSON) until you're ready to generate issues
|
|
704
|
+
- When ready, output CLAUDE_QUEUE_READY on its own line followed by ONLY the JSON array"
|
|
705
|
+
|
|
706
|
+
echo -e "${BOLD}Interactive issue creation${NC}"
|
|
707
|
+
echo -e "${DIM}Answer Claude's questions. Type 'done' to generate issues at any time.${NC}"
|
|
708
|
+
echo ""
|
|
709
|
+
|
|
710
|
+
while [ "$turn" -lt "$max_turns" ]; do
|
|
711
|
+
turn=$((turn + 1))
|
|
712
|
+
|
|
713
|
+
local prompt
|
|
714
|
+
if [ -z "$conversation" ]; then
|
|
715
|
+
prompt="${system_prompt}
|
|
716
|
+
|
|
717
|
+
Start by asking your first question."
|
|
718
|
+
else
|
|
719
|
+
prompt="${system_prompt}
|
|
720
|
+
|
|
721
|
+
Conversation so far:
|
|
722
|
+
${conversation}
|
|
723
|
+
|
|
724
|
+
Continue the interview or, if you have enough information, output CLAUDE_QUEUE_READY followed by the JSON array."
|
|
725
|
+
fi
|
|
726
|
+
|
|
727
|
+
local output
|
|
728
|
+
# shellcheck disable=SC2086
|
|
729
|
+
output=$(claude -p "$prompt" $MODEL_FLAG 2>/dev/null)
|
|
730
|
+
|
|
731
|
+
if echo "$output" | grep -q "CLAUDE_QUEUE_READY"; then
|
|
732
|
+
local json_part
|
|
733
|
+
json_part=$(echo "$output" | sed -n '/CLAUDE_QUEUE_READY/,$ p' | tail -n +2)
|
|
734
|
+
|
|
735
|
+
local json
|
|
736
|
+
if ! json=$(extract_json "$json_part"); then
|
|
737
|
+
log_error "Failed to parse generated issues as JSON"
|
|
738
|
+
exit 1
|
|
739
|
+
fi
|
|
740
|
+
|
|
741
|
+
echo "$json"
|
|
742
|
+
return 0
|
|
743
|
+
fi
|
|
744
|
+
|
|
745
|
+
echo -e "${BLUE}Claude:${NC} ${output}"
|
|
746
|
+
echo ""
|
|
747
|
+
|
|
748
|
+
local user_input
|
|
749
|
+
read -r -p "You: " user_input
|
|
750
|
+
|
|
751
|
+
if [ "$user_input" = "done" ]; then
|
|
752
|
+
conversation="${conversation}
|
|
753
|
+
Claude: ${output}
|
|
754
|
+
User: Please generate the issues now with what you know."
|
|
755
|
+
|
|
756
|
+
local final_prompt="${system_prompt}
|
|
757
|
+
|
|
758
|
+
Conversation so far:
|
|
759
|
+
${conversation}
|
|
760
|
+
|
|
761
|
+
The user wants you to generate the issues now. Output CLAUDE_QUEUE_READY followed by the JSON array."
|
|
762
|
+
|
|
763
|
+
local final_output
|
|
764
|
+
# shellcheck disable=SC2086
|
|
765
|
+
final_output=$(claude -p "$final_prompt" $MODEL_FLAG 2>/dev/null)
|
|
766
|
+
|
|
767
|
+
local final_json_part
|
|
768
|
+
final_json_part=$(echo "$final_output" | sed -n '/CLAUDE_QUEUE_READY/,$ p' | tail -n +2)
|
|
769
|
+
if [ -z "$final_json_part" ]; then
|
|
770
|
+
final_json_part="$final_output"
|
|
771
|
+
fi
|
|
772
|
+
|
|
773
|
+
local json
|
|
774
|
+
if ! json=$(extract_json "$final_json_part"); then
|
|
775
|
+
log_error "Failed to parse generated issues as JSON"
|
|
776
|
+
exit 1
|
|
777
|
+
fi
|
|
778
|
+
|
|
779
|
+
echo "$json"
|
|
780
|
+
return 0
|
|
781
|
+
fi
|
|
782
|
+
|
|
783
|
+
conversation="${conversation}
|
|
784
|
+
Claude: ${output}
|
|
785
|
+
User: ${user_input}"
|
|
786
|
+
done
|
|
787
|
+
|
|
788
|
+
log_warn "Reached maximum interview turns, generating issues with current information..."
|
|
789
|
+
|
|
790
|
+
local final_prompt="${system_prompt}
|
|
791
|
+
|
|
792
|
+
Conversation so far:
|
|
793
|
+
${conversation}
|
|
794
|
+
|
|
795
|
+
You've reached the maximum number of questions. Output CLAUDE_QUEUE_READY followed by the JSON array now."
|
|
796
|
+
|
|
797
|
+
local final_output
|
|
798
|
+
# shellcheck disable=SC2086
|
|
799
|
+
final_output=$(claude -p "$final_prompt" $MODEL_FLAG 2>/dev/null)
|
|
800
|
+
|
|
801
|
+
local final_json_part
|
|
802
|
+
final_json_part=$(echo "$final_output" | sed -n '/CLAUDE_QUEUE_READY/,$ p' | tail -n +2)
|
|
803
|
+
if [ -z "$final_json_part" ]; then
|
|
804
|
+
final_json_part="$final_output"
|
|
805
|
+
fi
|
|
806
|
+
|
|
807
|
+
local json
|
|
808
|
+
if ! json=$(extract_json "$final_json_part"); then
|
|
809
|
+
log_error "Failed to parse generated issues as JSON"
|
|
810
|
+
exit 1
|
|
811
|
+
fi
|
|
812
|
+
|
|
813
|
+
echo "$json"
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
preview_issues() {
|
|
817
|
+
local json="$1"
|
|
818
|
+
local count
|
|
819
|
+
count=$(echo "$json" | jq length)
|
|
820
|
+
|
|
821
|
+
echo ""
|
|
822
|
+
echo -e "${BOLD}═══ Issue Preview ═══${NC}"
|
|
823
|
+
echo ""
|
|
824
|
+
|
|
825
|
+
for i in $(seq 0 $((count - 1))); do
|
|
826
|
+
local title labels body
|
|
827
|
+
title=$(echo "$json" | jq -r ".[$i].title")
|
|
828
|
+
labels=$(echo "$json" | jq -r ".[$i].labels // [] | join(\", \")")
|
|
829
|
+
body=$(echo "$json" | jq -r ".[$i].body" | head -3)
|
|
830
|
+
|
|
831
|
+
echo -e " ${BOLD}$((i + 1)). ${title}${NC}"
|
|
832
|
+
if [ -n "$labels" ]; then
|
|
833
|
+
echo -e " ${DIM}Labels: ${labels}${NC}"
|
|
834
|
+
fi
|
|
835
|
+
echo -e " ${DIM}$(echo "$body" | head -1)${NC}"
|
|
836
|
+
echo ""
|
|
837
|
+
done
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
confirm_and_create() {
|
|
841
|
+
local json="$1"
|
|
842
|
+
local extra_label="$2"
|
|
843
|
+
local count
|
|
844
|
+
count=$(echo "$json" | jq length)
|
|
845
|
+
|
|
846
|
+
local prompt_text="Create ${count} issue(s)? [y/N] "
|
|
847
|
+
read -r -p "$prompt_text" confirm
|
|
848
|
+
|
|
849
|
+
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
|
|
850
|
+
log "Cancelled."
|
|
851
|
+
exit 0
|
|
852
|
+
fi
|
|
853
|
+
|
|
854
|
+
echo ""
|
|
855
|
+
|
|
856
|
+
for i in $(seq 0 $((count - 1))); do
|
|
857
|
+
local title body
|
|
858
|
+
title=$(echo "$json" | jq -r ".[$i].title")
|
|
859
|
+
body=$(echo "$json" | jq -r ".[$i].body")
|
|
860
|
+
|
|
861
|
+
local label_args=()
|
|
862
|
+
local issue_labels
|
|
863
|
+
issue_labels=$(echo "$json" | jq -r ".[$i].labels // [] | .[]")
|
|
864
|
+
while IFS= read -r lbl; do
|
|
865
|
+
if [ -n "$lbl" ]; then
|
|
866
|
+
label_args+=(--label "$lbl")
|
|
867
|
+
fi
|
|
868
|
+
done <<< "$issue_labels"
|
|
869
|
+
|
|
870
|
+
if [ -n "$extra_label" ]; then
|
|
871
|
+
label_args+=(--label "$extra_label")
|
|
872
|
+
fi
|
|
873
|
+
|
|
874
|
+
local issue_url
|
|
875
|
+
issue_url=$(gh issue create --title "$title" --body "$body" "${label_args[@]}" 2>&1)
|
|
876
|
+
log_success "Created: ${issue_url}"
|
|
877
|
+
done
|
|
878
|
+
|
|
879
|
+
echo ""
|
|
880
|
+
log_success "Created ${count} issue(s)"
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
cmd_create() {
|
|
884
|
+
local interactive=false
|
|
885
|
+
local extra_label=""
|
|
886
|
+
local user_text=""
|
|
887
|
+
|
|
888
|
+
while [[ $# -gt 0 ]]; do
|
|
889
|
+
case $1 in
|
|
890
|
+
-i|--interactive) interactive=true; shift ;;
|
|
891
|
+
--label) extra_label="$2"; shift 2 ;;
|
|
892
|
+
--model) MODEL_FLAG="--model $2"; shift 2 ;;
|
|
893
|
+
-h|--help) show_create_help; exit 0 ;;
|
|
894
|
+
-*) echo "Unknown option: $1"; echo ""; show_create_help; exit 1 ;;
|
|
895
|
+
*) user_text="$1"; shift ;;
|
|
896
|
+
esac
|
|
897
|
+
done
|
|
898
|
+
|
|
899
|
+
create_preflight
|
|
900
|
+
|
|
901
|
+
local json
|
|
902
|
+
|
|
903
|
+
if [ "$interactive" = true ]; then
|
|
904
|
+
json=$(create_interactive)
|
|
905
|
+
elif [ -n "$user_text" ]; then
|
|
906
|
+
json=$(create_from_text "$user_text")
|
|
907
|
+
else
|
|
908
|
+
echo -e "${BOLD}Describe what issues you want to create.${NC}"
|
|
909
|
+
echo -e "${DIM}Type or paste your text, then press Ctrl+D when done.${NC}"
|
|
910
|
+
echo ""
|
|
911
|
+
user_text=$(cat)
|
|
912
|
+
if [ -z "$user_text" ]; then
|
|
913
|
+
log_error "No input provided"
|
|
914
|
+
exit 1
|
|
915
|
+
fi
|
|
916
|
+
json=$(create_from_text "$user_text")
|
|
917
|
+
fi
|
|
918
|
+
|
|
919
|
+
preview_issues "$json"
|
|
920
|
+
confirm_and_create "$json" "$extra_label"
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
# --- Subcommand routing ---
|
|
924
|
+
|
|
925
|
+
SUBCOMMAND=""
|
|
926
|
+
if [[ $# -gt 0 ]] && [[ "$1" != -* ]]; then
|
|
927
|
+
SUBCOMMAND="$1"; shift
|
|
928
|
+
fi
|
|
929
|
+
|
|
930
|
+
case "$SUBCOMMAND" in
|
|
931
|
+
"")
|
|
932
|
+
while [[ $# -gt 0 ]]; do
|
|
933
|
+
case $1 in
|
|
934
|
+
--max-retries) MAX_RETRIES="$2"; shift 2 ;;
|
|
935
|
+
--max-turns) MAX_TURNS="$2"; shift 2 ;;
|
|
936
|
+
--label) ISSUE_FILTER="$2"; shift 2 ;;
|
|
937
|
+
--model) MODEL_FLAG="--model $2"; shift 2 ;;
|
|
938
|
+
-v|--version) echo "claude-queue v${VERSION}"; exit 0 ;;
|
|
939
|
+
-h|--help) show_help; exit 0 ;;
|
|
940
|
+
*) echo "Unknown option: $1"; exit 1 ;;
|
|
941
|
+
esac
|
|
942
|
+
done
|
|
943
|
+
main
|
|
944
|
+
;;
|
|
945
|
+
create)
|
|
946
|
+
cmd_create "$@"
|
|
947
|
+
;;
|
|
948
|
+
*)
|
|
949
|
+
echo "Unknown command: $SUBCOMMAND"
|
|
950
|
+
echo ""
|
|
951
|
+
show_help
|
|
952
|
+
exit 1
|
|
953
|
+
;;
|
|
954
|
+
esac
|