claude-code-workflow 6.3.8 → 6.3.9
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/.claude/agents/issue-plan-agent.md +89 -54
- package/.claude/agents/issue-queue-agent.md +42 -50
- package/.claude/commands/issue/plan.md +61 -25
- package/.claude/workflows/cli-templates/schemas/queue-schema.json +3 -3
- package/.claude/workflows/cli-templates/schemas/solution-schema.json +70 -3
- package/ccw/dist/commands/issue.d.ts.map +1 -1
- package/ccw/dist/commands/issue.js.map +1 -1
- package/ccw/dist/core/routes/issue-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/issue-routes.js +68 -0
- package/ccw/dist/core/routes/issue-routes.js.map +1 -1
- package/ccw/src/commands/issue.ts +19 -2
- package/ccw/src/core/routes/issue-routes.ts +76 -0
- package/ccw/src/templates/dashboard-css/32-issue-manager.css +310 -1
- package/ccw/src/templates/dashboard-js/views/issue-manager.js +252 -0
- package/package.json +1 -1
- package/.claude/workflows/cli-templates/schemas/issue-task-jsonl-schema.json +0 -136
- package/.claude/workflows/cli-templates/schemas/solutions-jsonl-schema.json +0 -125
|
@@ -26,7 +26,7 @@ color: green
|
|
|
26
26
|
- Dependency DAG validation
|
|
27
27
|
- Auto-bind for single solution, return for selection on multiple
|
|
28
28
|
|
|
29
|
-
**Key Principle**: Generate tasks conforming to schema with quantified
|
|
29
|
+
**Key Principle**: Generate tasks conforming to schema with quantified acceptance criteria.
|
|
30
30
|
|
|
31
31
|
---
|
|
32
32
|
|
|
@@ -71,11 +71,17 @@ function analyzeIssue(issue) {
|
|
|
71
71
|
issue_id: issue.id,
|
|
72
72
|
requirements: extractRequirements(issue.description),
|
|
73
73
|
scope: inferScope(issue.title, issue.description),
|
|
74
|
-
complexity: determineComplexity(issue) // Low | Medium | High
|
|
74
|
+
complexity: determineComplexity(issue), // Low | Medium | High
|
|
75
|
+
lifecycle: issue.lifecycle_requirements // User preferences for test/commit
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
```
|
|
78
79
|
|
|
80
|
+
**Step 3**: Apply lifecycle requirements to tasks
|
|
81
|
+
- `lifecycle.test_strategy` → Configure `test.unit`, `test.commands`
|
|
82
|
+
- `lifecycle.commit_strategy` → Configure `commit.type`, `commit.scope`
|
|
83
|
+
- `lifecycle.regression_scope` → Configure `regression` array
|
|
84
|
+
|
|
79
85
|
**Complexity Rules**:
|
|
80
86
|
| Complexity | Files | Tasks |
|
|
81
87
|
|------------|-------|-------|
|
|
@@ -100,26 +106,76 @@ mcp__ace-tool__search_context({
|
|
|
100
106
|
- [ ] Discover dependencies
|
|
101
107
|
- [ ] Locate test patterns
|
|
102
108
|
|
|
103
|
-
**Fallback**: ACE →
|
|
109
|
+
**Fallback Chain**: ACE → smart_search → Grep → rg → Glob
|
|
110
|
+
|
|
111
|
+
| Tool | When to Use |
|
|
112
|
+
|------|-------------|
|
|
113
|
+
| `mcp__ace-tool__search_context` | Semantic search (primary) |
|
|
114
|
+
| `mcp__ccw-tools__smart_search` | Symbol/pattern search |
|
|
115
|
+
| `Grep` | Exact regex matching |
|
|
116
|
+
| `rg` / `grep` | CLI fallback |
|
|
117
|
+
| `Glob` | File path discovery |
|
|
104
118
|
|
|
105
119
|
#### Phase 3: Solution Planning
|
|
106
120
|
|
|
121
|
+
**Multi-Solution Generation**:
|
|
122
|
+
|
|
123
|
+
Generate multiple candidate solutions when:
|
|
124
|
+
- Issue complexity is HIGH
|
|
125
|
+
- Multiple valid implementation approaches exist
|
|
126
|
+
- Trade-offs between approaches (performance vs simplicity, etc.)
|
|
127
|
+
|
|
128
|
+
| Condition | Solutions |
|
|
129
|
+
|-----------|-----------|
|
|
130
|
+
| Low complexity, single approach | 1 solution, auto-bind |
|
|
131
|
+
| Medium complexity, clear path | 1-2 solutions |
|
|
132
|
+
| High complexity, multiple approaches | 2-3 solutions, user selection |
|
|
133
|
+
|
|
134
|
+
**Solution Evaluation** (for each candidate):
|
|
135
|
+
```javascript
|
|
136
|
+
{
|
|
137
|
+
analysis: {
|
|
138
|
+
risk: "low|medium|high", // Implementation risk
|
|
139
|
+
impact: "low|medium|high", // Scope of changes
|
|
140
|
+
complexity: "low|medium|high" // Technical complexity
|
|
141
|
+
},
|
|
142
|
+
score: 0.0-1.0 // Overall quality score (higher = recommended)
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Selection Flow**:
|
|
147
|
+
1. Generate all candidate solutions
|
|
148
|
+
2. Evaluate and score each
|
|
149
|
+
3. Single solution → auto-bind
|
|
150
|
+
4. Multiple solutions → return `pending_selection` for user choice
|
|
151
|
+
|
|
107
152
|
**Task Decomposition** following schema:
|
|
108
153
|
```javascript
|
|
109
154
|
function decomposeTasks(issue, exploration) {
|
|
110
155
|
return groups.map(group => ({
|
|
111
|
-
id: `
|
|
156
|
+
id: `T${taskId++}`, // Pattern: ^T[0-9]+$
|
|
112
157
|
title: group.title,
|
|
113
|
-
|
|
158
|
+
scope: inferScope(group), // Module path
|
|
159
|
+
action: inferAction(group), // Create | Update | Implement | ...
|
|
114
160
|
description: group.description,
|
|
115
|
-
|
|
161
|
+
modification_points: mapModificationPoints(group),
|
|
162
|
+
implementation: generateSteps(group), // Step-by-step guide
|
|
163
|
+
test: {
|
|
164
|
+
unit: generateUnitTests(group),
|
|
165
|
+
commands: ['npm test']
|
|
166
|
+
},
|
|
167
|
+
acceptance: {
|
|
168
|
+
criteria: generateCriteria(group), // Quantified checklist
|
|
169
|
+
verification: generateVerification(group)
|
|
170
|
+
},
|
|
171
|
+
commit: {
|
|
172
|
+
type: inferCommitType(group), // feat | fix | refactor | ...
|
|
173
|
+
scope: inferScope(group),
|
|
174
|
+
message_template: generateCommitMsg(group)
|
|
175
|
+
},
|
|
116
176
|
depends_on: inferDependencies(group, tasks),
|
|
117
|
-
delivery_criteria: generateDeliveryCriteria(group), // Quantified checklist
|
|
118
|
-
pause_criteria: identifyBlockers(group),
|
|
119
|
-
status: 'pending',
|
|
120
|
-
current_phase: 'analyze',
|
|
121
177
|
executor: inferExecutor(group),
|
|
122
|
-
priority: calculatePriority(group)
|
|
178
|
+
priority: calculatePriority(group) // 1-5 (1=highest)
|
|
123
179
|
}))
|
|
124
180
|
}
|
|
125
181
|
```
|
|
@@ -139,57 +195,34 @@ ccw issue bind <issue-id> --solution /tmp/sol.json
|
|
|
139
195
|
|
|
140
196
|
---
|
|
141
197
|
|
|
142
|
-
## 2. Output
|
|
198
|
+
## 2. Output Requirements
|
|
143
199
|
|
|
144
|
-
### 2.1
|
|
200
|
+
### 2.1 Generate Files (Primary)
|
|
145
201
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
"pending_selection": [{ "issue_id": "...", "solutions": [{ "id": "...", "description": "...", "task_count": N }] }],
|
|
150
|
-
"conflicts": [{ "file": "...", "issues": [...] }]
|
|
151
|
-
}
|
|
202
|
+
**Solution file per issue**:
|
|
203
|
+
```
|
|
204
|
+
.workflow/issues/solutions/{issue-id}.jsonl
|
|
152
205
|
```
|
|
153
206
|
|
|
154
|
-
|
|
207
|
+
Each line is a solution JSON containing tasks. Schema: `cat .claude/workflows/cli-templates/schemas/solution-schema.json`
|
|
208
|
+
|
|
209
|
+
### 2.2 Binding
|
|
155
210
|
|
|
156
211
|
| Scenario | Action |
|
|
157
212
|
|----------|--------|
|
|
158
|
-
| Single solution |
|
|
159
|
-
| Multiple solutions | Register only, return for
|
|
160
|
-
|
|
161
|
-
### 2.3 Task Schema
|
|
213
|
+
| Single solution | `ccw issue bind <id> --solution <file>` (auto) |
|
|
214
|
+
| Multiple solutions | Register only, return for selection |
|
|
162
215
|
|
|
163
|
-
|
|
164
|
-
```bash
|
|
165
|
-
cat .claude/workflows/cli-templates/schemas/issue-task-jsonl-schema.json
|
|
166
|
-
```
|
|
216
|
+
### 2.3 Return Summary
|
|
167
217
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
- `delivery_criteria`: Checklist items defining completion
|
|
175
|
-
- `status`: pending | ready | in_progress | completed | failed | paused | skipped
|
|
176
|
-
- `current_phase`: analyze | implement | test | optimize | commit | done
|
|
177
|
-
- `executor`: agent | codex | gemini | auto
|
|
178
|
-
|
|
179
|
-
**Optional Fields**:
|
|
180
|
-
- `file_context`: Relevant files/globs
|
|
181
|
-
- `pause_criteria`: Conditions to halt execution
|
|
182
|
-
- `priority`: 1-5 (1=highest)
|
|
183
|
-
- `phase_results`: Results from each execution phase
|
|
184
|
-
|
|
185
|
-
### 2.4 Solution File Structure
|
|
186
|
-
|
|
187
|
-
```
|
|
188
|
-
.workflow/issues/solutions/{issue-id}.jsonl
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"bound": [{ "issue_id": "...", "solution_id": "...", "task_count": N }],
|
|
221
|
+
"pending_selection": [{ "issue_id": "...", "solutions": [{ "id": "SOL-001", "description": "...", "task_count": N }] }],
|
|
222
|
+
"conflicts": [{ "file": "...", "issues": [...] }]
|
|
223
|
+
}
|
|
189
224
|
```
|
|
190
225
|
|
|
191
|
-
Each line is a complete solution JSON.
|
|
192
|
-
|
|
193
226
|
---
|
|
194
227
|
|
|
195
228
|
## 3. Quality Standards
|
|
@@ -215,12 +248,14 @@ Each line is a complete solution JSON.
|
|
|
215
248
|
### 3.3 Guidelines
|
|
216
249
|
|
|
217
250
|
**ALWAYS**:
|
|
218
|
-
1. Read schema first: `cat .claude/workflows/cli-templates/schemas/
|
|
251
|
+
1. Read schema first: `cat .claude/workflows/cli-templates/schemas/solution-schema.json`
|
|
219
252
|
2. Use ACE semantic search as PRIMARY exploration tool
|
|
220
253
|
3. Fetch issue details via `ccw issue status <id> --json`
|
|
221
|
-
4. Quantify
|
|
254
|
+
4. Quantify acceptance.criteria with testable conditions
|
|
222
255
|
5. Validate DAG before output
|
|
223
|
-
6.
|
|
256
|
+
6. Evaluate each solution with `analysis` and `score`
|
|
257
|
+
7. Single solution → auto-bind; Multiple → return `pending_selection`
|
|
258
|
+
8. For HIGH complexity: generate 2-3 candidate solutions
|
|
224
259
|
|
|
225
260
|
**NEVER**:
|
|
226
261
|
1. Execute implementation (return plan only)
|
|
@@ -36,21 +36,21 @@ color: orange
|
|
|
36
36
|
```javascript
|
|
37
37
|
{
|
|
38
38
|
tasks: [{
|
|
39
|
+
key: string, // e.g., "GH-123:TASK-001"
|
|
39
40
|
issue_id: string, // e.g., "GH-123"
|
|
40
41
|
solution_id: string, // e.g., "SOL-001"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
file_context: string[],
|
|
46
|
-
depends_on: string[]
|
|
47
|
-
}
|
|
42
|
+
task_id: string, // e.g., "TASK-001"
|
|
43
|
+
type: string, // feature | bug | refactor | test | chore | docs
|
|
44
|
+
file_context: string[],
|
|
45
|
+
depends_on: string[] // composite keys, e.g., ["GH-123:TASK-001"]
|
|
48
46
|
}],
|
|
49
47
|
project_root?: string,
|
|
50
48
|
rebuild?: boolean
|
|
51
49
|
}
|
|
52
50
|
```
|
|
53
51
|
|
|
52
|
+
**Note**: Agent generates unique `item_id` (pattern: `T-{N}`) for queue output.
|
|
53
|
+
|
|
54
54
|
### 1.2 Execution Flow
|
|
55
55
|
|
|
56
56
|
```
|
|
@@ -76,19 +76,17 @@ function buildDependencyGraph(tasks) {
|
|
|
76
76
|
const fileModifications = new Map()
|
|
77
77
|
|
|
78
78
|
for (const item of tasks) {
|
|
79
|
-
|
|
80
|
-
graph.set(key, { ...item, key, inDegree: 0, outEdges: [] })
|
|
79
|
+
graph.set(item.key, { ...item, inDegree: 0, outEdges: [] })
|
|
81
80
|
|
|
82
|
-
for (const file of item.
|
|
81
|
+
for (const file of item.file_context || []) {
|
|
83
82
|
if (!fileModifications.has(file)) fileModifications.set(file, [])
|
|
84
|
-
fileModifications.get(file).push(key)
|
|
83
|
+
fileModifications.get(file).push(item.key)
|
|
85
84
|
}
|
|
86
85
|
}
|
|
87
86
|
|
|
88
87
|
// Add dependency edges
|
|
89
88
|
for (const [key, node] of graph) {
|
|
90
|
-
for (const
|
|
91
|
-
const depKey = `${node.issue_id}:${dep}`
|
|
89
|
+
for (const depKey of node.depends_on || []) {
|
|
92
90
|
if (graph.has(depKey)) {
|
|
93
91
|
graph.get(depKey).outEdges.push(key)
|
|
94
92
|
node.inDegree++
|
|
@@ -128,6 +126,16 @@ function detectConflicts(fileModifications, graph) {
|
|
|
128
126
|
|
|
129
127
|
### 2.4 Semantic Priority
|
|
130
128
|
|
|
129
|
+
**Base Priority Mapping** (task.priority 1-5 → base score):
|
|
130
|
+
| task.priority | Base Score | Meaning |
|
|
131
|
+
|---------------|------------|---------|
|
|
132
|
+
| 1 | 0.8 | Highest |
|
|
133
|
+
| 2 | 0.65 | High |
|
|
134
|
+
| 3 | 0.5 | Medium |
|
|
135
|
+
| 4 | 0.35 | Low |
|
|
136
|
+
| 5 | 0.2 | Lowest |
|
|
137
|
+
|
|
138
|
+
**Action-based Boost** (applied to base score):
|
|
131
139
|
| Factor | Boost |
|
|
132
140
|
|--------|-------|
|
|
133
141
|
| Create action | +0.2 |
|
|
@@ -140,6 +148,8 @@ function detectConflicts(fileModifications, graph) {
|
|
|
140
148
|
| Test action | -0.1 |
|
|
141
149
|
| Delete action | -0.15 |
|
|
142
150
|
|
|
151
|
+
**Formula**: `semantic_priority = clamp(baseScore + sum(boosts), 0.0, 1.0)`
|
|
152
|
+
|
|
143
153
|
### 2.5 Group Assignment
|
|
144
154
|
|
|
145
155
|
- **Parallel (P*)**: Tasks with no dependencies or conflicts between them
|
|
@@ -147,48 +157,29 @@ function detectConflicts(fileModifications, graph) {
|
|
|
147
157
|
|
|
148
158
|
---
|
|
149
159
|
|
|
150
|
-
## 3. Output
|
|
160
|
+
## 3. Output Requirements
|
|
151
161
|
|
|
152
|
-
### 3.1
|
|
162
|
+
### 3.1 Generate Files (Primary)
|
|
153
163
|
|
|
154
|
-
|
|
155
|
-
```
|
|
156
|
-
|
|
164
|
+
**Queue files**:
|
|
165
|
+
```
|
|
166
|
+
.workflow/issues/queues/{queue-id}.json # Full queue with tasks, conflicts, groups
|
|
167
|
+
.workflow/issues/queues/index.json # Update with new queue entry
|
|
157
168
|
```
|
|
158
169
|
|
|
159
|
-
|
|
170
|
+
Queue ID format: `QUE-YYYYMMDD-HHMMSS` (UTC timestamp)
|
|
171
|
+
|
|
172
|
+
Schema: `cat .claude/workflows/cli-templates/schemas/queue-schema.json`
|
|
173
|
+
|
|
174
|
+
### 3.2 Return Summary
|
|
160
175
|
|
|
161
176
|
```json
|
|
162
177
|
{
|
|
163
|
-
"
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
"status": "pending",
|
|
169
|
-
"execution_order": 1,
|
|
170
|
-
"execution_group": "P1",
|
|
171
|
-
"depends_on": [],
|
|
172
|
-
"semantic_priority": 0.7
|
|
173
|
-
}],
|
|
174
|
-
"conflicts": [{
|
|
175
|
-
"file": "src/auth.ts",
|
|
176
|
-
"tasks": ["GH-123:TASK-001", "GH-124:TASK-002"],
|
|
177
|
-
"resolution": "sequential",
|
|
178
|
-
"resolution_order": ["GH-123:TASK-001", "GH-124:TASK-002"],
|
|
179
|
-
"rationale": "TASK-001 creates file before TASK-002 updates",
|
|
180
|
-
"resolved": true
|
|
181
|
-
}],
|
|
182
|
-
"execution_groups": [
|
|
183
|
-
{ "id": "P1", "type": "parallel", "task_count": 3, "tasks": ["T-1", "T-2", "T-3"] },
|
|
184
|
-
{ "id": "S2", "type": "sequential", "task_count": 2, "tasks": ["T-4", "T-5"] }
|
|
185
|
-
],
|
|
186
|
-
"_metadata": {
|
|
187
|
-
"total_tasks": 5,
|
|
188
|
-
"total_conflicts": 1,
|
|
189
|
-
"resolved_conflicts": 1,
|
|
190
|
-
"timestamp": "2025-12-27T10:00:00Z"
|
|
191
|
-
}
|
|
178
|
+
"queue_id": "QUE-20251227-143000",
|
|
179
|
+
"total_tasks": N,
|
|
180
|
+
"execution_groups": [{ "id": "P1", "type": "parallel", "count": N }],
|
|
181
|
+
"conflicts_resolved": N,
|
|
182
|
+
"issues_queued": ["GH-123", "GH-124"]
|
|
192
183
|
}
|
|
193
184
|
```
|
|
194
185
|
|
|
@@ -231,5 +222,6 @@ cat .claude/workflows/cli-templates/schemas/queue-schema.json
|
|
|
231
222
|
5. Merge conflicting tasks in parallel group
|
|
232
223
|
|
|
233
224
|
**OUTPUT**:
|
|
234
|
-
1. Write queue
|
|
235
|
-
2.
|
|
225
|
+
1. Write `.workflow/issues/queues/{queue-id}.json`
|
|
226
|
+
2. Update `.workflow/issues/queues/index.json`
|
|
227
|
+
3. Return summary with `queue_id`, `total_tasks`, `execution_groups`, `conflicts_resolved`, `issues_queued`
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: plan
|
|
3
3
|
description: Batch plan issue resolution using issue-plan-agent (explore + plan closed-loop)
|
|
4
|
-
argument-hint: "<issue-id>[,<issue-id>,...] [--batch-size 3]
|
|
4
|
+
argument-hint: "--all-pending <issue-id>[,<issue-id>,...] [--batch-size 3] "
|
|
5
5
|
allowed-tools: TodoWrite(*), Task(*), SlashCommand(*), AskUserQuestion(*), Bash(*), Read(*), Write(*)
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -29,8 +29,8 @@ Unified planning command using **issue-plan-agent** that combines exploration an
|
|
|
29
29
|
- [ ] Solution file generated for each issue
|
|
30
30
|
- [ ] Single solution → auto-bound via `ccw issue bind`
|
|
31
31
|
- [ ] Multiple solutions → returned for user selection
|
|
32
|
-
- [ ] Tasks conform to schema: `cat .claude/workflows/cli-templates/schemas/
|
|
33
|
-
- [ ] Each task has quantified `
|
|
32
|
+
- [ ] Tasks conform to schema: `cat .claude/workflows/cli-templates/schemas/solution-schema.json`
|
|
33
|
+
- [ ] Each task has quantified `acceptance.criteria`
|
|
34
34
|
|
|
35
35
|
## Core Capabilities
|
|
36
36
|
|
|
@@ -70,9 +70,9 @@ Unified planning command using **issue-plan-agent** that combines exploration an
|
|
|
70
70
|
```
|
|
71
71
|
Phase 1: Issue Loading
|
|
72
72
|
├─ Parse input (single, comma-separated, or --all-pending)
|
|
73
|
-
├─
|
|
73
|
+
├─ Fetch issue metadata (ID, title, tags)
|
|
74
74
|
├─ Validate issues exist (create if needed)
|
|
75
|
-
└─ Group
|
|
75
|
+
└─ Group by similarity (shared tags or title keywords, max 3 per batch)
|
|
76
76
|
|
|
77
77
|
Phase 2: Unified Explore + Plan (issue-plan-agent)
|
|
78
78
|
├─ Launch issue-plan-agent per batch
|
|
@@ -97,41 +97,71 @@ Phase 4: Summary
|
|
|
97
97
|
|
|
98
98
|
## Implementation
|
|
99
99
|
|
|
100
|
-
### Phase 1: Issue Loading (
|
|
100
|
+
### Phase 1: Issue Loading (ID + Title + Tags)
|
|
101
101
|
|
|
102
102
|
```javascript
|
|
103
103
|
const batchSize = flags.batchSize || 3;
|
|
104
|
-
let
|
|
104
|
+
let issues = []; // {id, title, tags}
|
|
105
105
|
|
|
106
106
|
if (flags.allPending) {
|
|
107
|
-
// Get pending
|
|
108
|
-
const
|
|
109
|
-
|
|
107
|
+
// Get pending issues with metadata via CLI (JSON output)
|
|
108
|
+
const result = Bash(`ccw issue list --status pending,registered --json`).trim();
|
|
109
|
+
const parsed = result ? JSON.parse(result) : [];
|
|
110
|
+
issues = parsed.map(i => ({ id: i.id, title: i.title || '', tags: i.tags || [] }));
|
|
110
111
|
|
|
111
|
-
if (
|
|
112
|
+
if (issues.length === 0) {
|
|
112
113
|
console.log('No pending issues found.');
|
|
113
114
|
return;
|
|
114
115
|
}
|
|
115
|
-
console.log(`Found ${
|
|
116
|
+
console.log(`Found ${issues.length} pending issues`);
|
|
116
117
|
} else {
|
|
117
|
-
// Parse comma-separated issue IDs
|
|
118
|
-
|
|
118
|
+
// Parse comma-separated issue IDs, fetch metadata
|
|
119
|
+
const ids = userInput.includes(',')
|
|
119
120
|
? userInput.split(',').map(s => s.trim())
|
|
120
121
|
: [userInput.trim()];
|
|
121
122
|
|
|
122
|
-
|
|
123
|
-
for (const id of issueIds) {
|
|
123
|
+
for (const id of ids) {
|
|
124
124
|
Bash(`ccw issue init ${id} --title "Issue ${id}" 2>/dev/null || true`);
|
|
125
|
+
const info = Bash(`ccw issue status ${id} --json`).trim();
|
|
126
|
+
const parsed = info ? JSON.parse(info) : {};
|
|
127
|
+
issues.push({ id, title: parsed.title || '', tags: parsed.tags || [] });
|
|
125
128
|
}
|
|
126
129
|
}
|
|
127
130
|
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
131
|
+
// Intelligent grouping by similarity (tags → title keywords)
|
|
132
|
+
function groupBySimilarity(issues, maxSize) {
|
|
133
|
+
const batches = [];
|
|
134
|
+
const used = new Set();
|
|
135
|
+
|
|
136
|
+
for (const issue of issues) {
|
|
137
|
+
if (used.has(issue.id)) continue;
|
|
138
|
+
|
|
139
|
+
const batch = [issue];
|
|
140
|
+
used.add(issue.id);
|
|
141
|
+
const issueTags = new Set(issue.tags);
|
|
142
|
+
const issueWords = new Set(issue.title.toLowerCase().split(/\s+/));
|
|
143
|
+
|
|
144
|
+
// Find similar issues
|
|
145
|
+
for (const other of issues) {
|
|
146
|
+
if (used.has(other.id) || batch.length >= maxSize) continue;
|
|
147
|
+
|
|
148
|
+
// Similarity: shared tags or shared title keywords
|
|
149
|
+
const sharedTags = other.tags.filter(t => issueTags.has(t)).length;
|
|
150
|
+
const otherWords = other.title.toLowerCase().split(/\s+/);
|
|
151
|
+
const sharedWords = otherWords.filter(w => issueWords.has(w) && w.length > 3).length;
|
|
152
|
+
|
|
153
|
+
if (sharedTags > 0 || sharedWords >= 2) {
|
|
154
|
+
batch.push(other);
|
|
155
|
+
used.add(other.id);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
batches.push(batch);
|
|
159
|
+
}
|
|
160
|
+
return batches;
|
|
132
161
|
}
|
|
133
162
|
|
|
134
|
-
|
|
163
|
+
const batches = groupBySimilarity(issues, batchSize);
|
|
164
|
+
console.log(`Processing ${issues.length} issues in ${batches.length} batch(es) (grouped by similarity)`);
|
|
135
165
|
|
|
136
166
|
TodoWrite({
|
|
137
167
|
todos: batches.map((_, i) => ({
|
|
@@ -151,11 +181,16 @@ const pendingSelections = []; // Collect multi-solution issues for user selecti
|
|
|
151
181
|
for (const [batchIndex, batch] of batches.entries()) {
|
|
152
182
|
updateTodo(`Plan batch ${batchIndex + 1}`, 'in_progress');
|
|
153
183
|
|
|
184
|
+
// Build issue list with metadata for agent context
|
|
185
|
+
const issueList = batch.map(i => `- ${i.id}: ${i.title}${i.tags.length ? ` [${i.tags.join(', ')}]` : ''}`).join('\n');
|
|
186
|
+
|
|
154
187
|
// Build minimal prompt - agent handles exploration, planning, and binding
|
|
155
188
|
const issuePrompt = `
|
|
156
189
|
## Plan Issues
|
|
157
190
|
|
|
158
|
-
**
|
|
191
|
+
**Issues** (grouped by similarity):
|
|
192
|
+
${issueList}
|
|
193
|
+
|
|
159
194
|
**Project Root**: ${process.cwd()}
|
|
160
195
|
|
|
161
196
|
### Steps
|
|
@@ -164,7 +199,7 @@ for (const [batchIndex, batch] of batches.entries()) {
|
|
|
164
199
|
3. Register & bind: \`ccw issue bind <id> --solution <file>\`
|
|
165
200
|
|
|
166
201
|
### Generate Files
|
|
167
|
-
\`.workflow/issues/solutions/{issue-id}.jsonl\` - Solution with tasks (schema: cat .claude/workflows/cli-templates/schemas/
|
|
202
|
+
\`.workflow/issues/solutions/{issue-id}.jsonl\` - Solution with tasks (schema: cat .claude/workflows/cli-templates/schemas/solution-schema.json)
|
|
168
203
|
|
|
169
204
|
### Binding Rules
|
|
170
205
|
- **Single solution**: Auto-bind via \`ccw issue bind <id> --solution <file>\`
|
|
@@ -181,10 +216,11 @@ for (const [batchIndex, batch] of batches.entries()) {
|
|
|
181
216
|
`;
|
|
182
217
|
|
|
183
218
|
// Launch issue-plan-agent - agent writes solutions directly
|
|
219
|
+
const batchIds = batch.map(i => i.id);
|
|
184
220
|
const result = Task(
|
|
185
221
|
subagent_type="issue-plan-agent",
|
|
186
222
|
run_in_background=false,
|
|
187
|
-
description=`Explore & plan ${batch.length} issues`,
|
|
223
|
+
description=`Explore & plan ${batch.length} issues: ${batchIds.join(', ')}`,
|
|
188
224
|
prompt=issuePrompt
|
|
189
225
|
);
|
|
190
226
|
|
|
@@ -244,7 +280,7 @@ const plannedIds = Bash(`ccw issue list --status planned --ids`).trim();
|
|
|
244
280
|
const plannedCount = plannedIds ? plannedIds.split('\n').length : 0;
|
|
245
281
|
|
|
246
282
|
console.log(`
|
|
247
|
-
## Done: ${
|
|
283
|
+
## Done: ${issues.length} issues → ${plannedCount} planned
|
|
248
284
|
|
|
249
285
|
Next: \`/issue:queue\` → \`/issue:execute\`
|
|
250
286
|
`);
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
"description": "Ordered list of tasks to execute",
|
|
10
10
|
"items": {
|
|
11
11
|
"type": "object",
|
|
12
|
-
"required": ["
|
|
12
|
+
"required": ["item_id", "issue_id", "solution_id", "task_id", "status"],
|
|
13
13
|
"properties": {
|
|
14
|
-
"
|
|
14
|
+
"item_id": {
|
|
15
15
|
"type": "string",
|
|
16
|
-
"pattern": "^
|
|
16
|
+
"pattern": "^T-[0-9]+$",
|
|
17
17
|
"description": "Unique queue item identifier"
|
|
18
18
|
},
|
|
19
19
|
"issue_id": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"description": "Task breakdown for this solution",
|
|
24
24
|
"items": {
|
|
25
25
|
"type": "object",
|
|
26
|
-
"required": ["id", "title", "scope", "action", "acceptance"],
|
|
26
|
+
"required": ["id", "title", "scope", "action", "implementation", "acceptance"],
|
|
27
27
|
"properties": {
|
|
28
28
|
"id": {
|
|
29
29
|
"type": "string",
|
|
@@ -61,10 +61,40 @@
|
|
|
61
61
|
"items": { "type": "string" },
|
|
62
62
|
"description": "Step-by-step implementation guide"
|
|
63
63
|
},
|
|
64
|
-
"
|
|
64
|
+
"test": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"description": "Test requirements",
|
|
67
|
+
"properties": {
|
|
68
|
+
"unit": { "type": "array", "items": { "type": "string" } },
|
|
69
|
+
"integration": { "type": "array", "items": { "type": "string" } },
|
|
70
|
+
"commands": { "type": "array", "items": { "type": "string" } },
|
|
71
|
+
"coverage_target": { "type": "number" }
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"regression": {
|
|
65
75
|
"type": "array",
|
|
66
76
|
"items": { "type": "string" },
|
|
67
|
-
"description": "
|
|
77
|
+
"description": "Regression check points"
|
|
78
|
+
},
|
|
79
|
+
"acceptance": {
|
|
80
|
+
"type": "object",
|
|
81
|
+
"description": "Acceptance criteria & verification",
|
|
82
|
+
"required": ["criteria", "verification"],
|
|
83
|
+
"properties": {
|
|
84
|
+
"criteria": { "type": "array", "items": { "type": "string" } },
|
|
85
|
+
"verification": { "type": "array", "items": { "type": "string" } },
|
|
86
|
+
"manual_checks": { "type": "array", "items": { "type": "string" } }
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"commit": {
|
|
90
|
+
"type": "object",
|
|
91
|
+
"description": "Commit specification",
|
|
92
|
+
"properties": {
|
|
93
|
+
"type": { "type": "string", "enum": ["feat", "fix", "refactor", "test", "docs", "chore"] },
|
|
94
|
+
"scope": { "type": "string" },
|
|
95
|
+
"message_template": { "type": "string" },
|
|
96
|
+
"breaking": { "type": "boolean" }
|
|
97
|
+
}
|
|
68
98
|
},
|
|
69
99
|
"depends_on": {
|
|
70
100
|
"type": "array",
|
|
@@ -80,6 +110,28 @@
|
|
|
80
110
|
"type": "string",
|
|
81
111
|
"enum": ["codex", "gemini", "agent", "auto"],
|
|
82
112
|
"default": "auto"
|
|
113
|
+
},
|
|
114
|
+
"lifecycle_status": {
|
|
115
|
+
"type": "object",
|
|
116
|
+
"description": "Lifecycle phase tracking",
|
|
117
|
+
"properties": {
|
|
118
|
+
"implemented": { "type": "boolean" },
|
|
119
|
+
"tested": { "type": "boolean" },
|
|
120
|
+
"regression_passed": { "type": "boolean" },
|
|
121
|
+
"accepted": { "type": "boolean" },
|
|
122
|
+
"committed": { "type": "boolean" }
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"status": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"enum": ["pending", "ready", "executing", "completed", "failed", "blocked"],
|
|
128
|
+
"default": "pending"
|
|
129
|
+
},
|
|
130
|
+
"priority": {
|
|
131
|
+
"type": "integer",
|
|
132
|
+
"minimum": 1,
|
|
133
|
+
"maximum": 5,
|
|
134
|
+
"default": 3
|
|
83
135
|
}
|
|
84
136
|
}
|
|
85
137
|
}
|
|
@@ -97,6 +149,21 @@
|
|
|
97
149
|
"integration_points": { "type": "string" }
|
|
98
150
|
}
|
|
99
151
|
},
|
|
152
|
+
"analysis": {
|
|
153
|
+
"type": "object",
|
|
154
|
+
"description": "Solution risk assessment",
|
|
155
|
+
"properties": {
|
|
156
|
+
"risk": { "type": "string", "enum": ["low", "medium", "high"] },
|
|
157
|
+
"impact": { "type": "string", "enum": ["low", "medium", "high"] },
|
|
158
|
+
"complexity": { "type": "string", "enum": ["low", "medium", "high"] }
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
"score": {
|
|
162
|
+
"type": "number",
|
|
163
|
+
"minimum": 0,
|
|
164
|
+
"maximum": 1,
|
|
165
|
+
"description": "Solution quality score (0.0-1.0)"
|
|
166
|
+
},
|
|
100
167
|
"status": {
|
|
101
168
|
"type": "string",
|
|
102
169
|
"enum": ["draft", "candidate", "bound", "queued", "executing", "completed", "failed"],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue.d.ts","sourceRoot":"","sources":["../../src/commands/issue.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"issue.d.ts","sourceRoot":"","sources":["../../src/commands/issue.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAiLH,UAAU,YAAY;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAw+BD,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,EACvB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,IAAI,CAAC,CAiFf"}
|