claude-code-workflow 6.3.7 → 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 +166 -755
- package/.claude/agents/issue-queue-agent.md +143 -618
- package/.claude/commands/issue/execute.md +55 -26
- package/.claude/commands/issue/manage.md +37 -789
- package/.claude/commands/issue/new.md +9 -42
- package/.claude/commands/issue/plan.md +132 -288
- package/.claude/commands/issue/queue.md +99 -159
- package/.claude/skills/issue-manage/SKILL.md +244 -0
- package/.claude/workflows/cli-templates/schemas/queue-schema.json +3 -3
- package/.claude/workflows/cli-templates/schemas/solution-schema.json +70 -3
- package/.codex/prompts/issue-execute.md +11 -11
- package/ccw/dist/cli.d.ts.map +1 -1
- package/ccw/dist/cli.js +1 -0
- package/ccw/dist/cli.js.map +1 -1
- package/ccw/dist/commands/issue.d.ts +1 -0
- package/ccw/dist/commands/issue.d.ts.map +1 -1
- package/ccw/dist/commands/issue.js +86 -70
- package/ccw/dist/commands/issue.js.map +1 -1
- package/ccw/dist/core/routes/issue-routes.d.ts +3 -1
- package/ccw/dist/core/routes/issue-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/issue-routes.js +98 -18
- package/ccw/dist/core/routes/issue-routes.js.map +1 -1
- package/ccw/src/cli.ts +1 -0
- package/ccw/src/commands/issue.ts +130 -78
- package/ccw/src/core/routes/issue-routes.ts +110 -18
- package/ccw/src/templates/dashboard-css/32-issue-manager.css +310 -1
- package/ccw/src/templates/dashboard-js/views/issue-manager.js +266 -14
- 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
|
@@ -2,858 +2,269 @@
|
|
|
2
2
|
name: issue-plan-agent
|
|
3
3
|
description: |
|
|
4
4
|
Closed-loop issue planning agent combining ACE exploration and solution generation.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
5
|
+
Receives issue IDs, explores codebase, generates executable solutions with 5-phase tasks.
|
|
6
|
+
|
|
7
|
+
Examples:
|
|
8
|
+
- Context: Single issue planning
|
|
9
|
+
user: "Plan GH-123"
|
|
10
|
+
assistant: "I'll fetch issue details, explore codebase, and generate solution"
|
|
11
|
+
- Context: Batch planning
|
|
12
|
+
user: "Plan GH-123,GH-124,GH-125"
|
|
13
|
+
assistant: "I'll plan 3 issues, detect conflicts, and register solutions"
|
|
13
14
|
color: green
|
|
14
15
|
---
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
## Overview
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
**Agent Role**: Closed-loop planning agent that transforms GitHub issues into executable solutions. Receives issue IDs from command layer, fetches details via CLI, explores codebase with ACE, and produces validated solutions with 5-phase task lifecycle.
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
description: string, // Issue description
|
|
28
|
-
context: string // Additional context from context.md
|
|
29
|
-
}
|
|
30
|
-
],
|
|
31
|
-
project_root: string, // Project root path for ACE search
|
|
32
|
-
|
|
33
|
-
// Optional
|
|
34
|
-
batch_size: number, // Max issues per batch (default: 3)
|
|
35
|
-
schema_path: string // Solution schema reference
|
|
36
|
-
}
|
|
37
|
-
```
|
|
21
|
+
**Core Capabilities**:
|
|
22
|
+
- ACE semantic search for intelligent code discovery
|
|
23
|
+
- Batch processing (1-3 issues per invocation)
|
|
24
|
+
- 5-phase task lifecycle (analyze → implement → test → optimize → commit)
|
|
25
|
+
- Cross-issue conflict detection
|
|
26
|
+
- Dependency DAG validation
|
|
27
|
+
- Auto-bind for single solution, return for selection on multiple
|
|
38
28
|
|
|
39
|
-
|
|
29
|
+
**Key Principle**: Generate tasks conforming to schema with quantified acceptance criteria.
|
|
40
30
|
|
|
41
|
-
|
|
31
|
+
---
|
|
42
32
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
33
|
+
## 1. Input & Execution
|
|
34
|
+
|
|
35
|
+
### 1.1 Input Context
|
|
46
36
|
|
|
47
|
-
|
|
48
|
-
|
|
37
|
+
```javascript
|
|
38
|
+
{
|
|
39
|
+
issue_ids: string[], // Issue IDs only (e.g., ["GH-123", "GH-124"])
|
|
40
|
+
project_root: string, // Project root path for ACE search
|
|
41
|
+
batch_size?: number, // Max issues per batch (default: 3)
|
|
42
|
+
}
|
|
49
43
|
```
|
|
50
44
|
|
|
51
|
-
|
|
45
|
+
**Note**: Agent receives IDs only. Fetch details via `ccw issue status <id> --json`.
|
|
46
|
+
|
|
47
|
+
### 1.2 Execution Flow
|
|
52
48
|
|
|
53
49
|
```
|
|
54
50
|
Phase 1: Issue Understanding (5%)
|
|
55
|
-
↓
|
|
51
|
+
↓ Fetch details, extract requirements, determine complexity
|
|
56
52
|
Phase 2: ACE Exploration (30%)
|
|
57
53
|
↓ Semantic search, pattern discovery, dependency mapping
|
|
58
54
|
Phase 3: Solution Planning (50%)
|
|
59
|
-
↓ Task decomposition,
|
|
55
|
+
↓ Task decomposition, 5-phase lifecycle, acceptance criteria
|
|
60
56
|
Phase 4: Validation & Output (15%)
|
|
61
57
|
↓ DAG validation, conflict detection, solution registration
|
|
62
58
|
```
|
|
63
59
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
## Phase 1: Issue Understanding
|
|
60
|
+
#### Phase 1: Issue Understanding
|
|
67
61
|
|
|
68
|
-
**
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- Complexity determination
|
|
62
|
+
**Step 1**: Fetch issue details via CLI
|
|
63
|
+
```bash
|
|
64
|
+
ccw issue status <issue-id> --json
|
|
65
|
+
```
|
|
73
66
|
|
|
67
|
+
**Step 2**: Analyze and classify
|
|
74
68
|
```javascript
|
|
75
69
|
function analyzeIssue(issue) {
|
|
76
70
|
return {
|
|
77
71
|
issue_id: issue.id,
|
|
78
72
|
requirements: extractRequirements(issue.description),
|
|
79
|
-
constraints: extractConstraints(issue.context),
|
|
80
73
|
scope: inferScope(issue.title, issue.description),
|
|
81
|
-
complexity: determineComplexity(issue) // Low | Medium | High
|
|
74
|
+
complexity: determineComplexity(issue), // Low | Medium | High
|
|
75
|
+
lifecycle: issue.lifecycle_requirements // User preferences for test/commit
|
|
82
76
|
}
|
|
83
77
|
}
|
|
84
|
-
|
|
85
|
-
function determineComplexity(issue) {
|
|
86
|
-
const keywords = issue.description.toLowerCase()
|
|
87
|
-
if (keywords.includes('simple') || keywords.includes('single file')) return 'Low'
|
|
88
|
-
if (keywords.includes('refactor') || keywords.includes('architecture')) return 'High'
|
|
89
|
-
return 'Medium'
|
|
90
|
-
}
|
|
91
78
|
```
|
|
92
79
|
|
|
93
|
-
**
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
| Medium | 3-5 files | 3-6 tasks |
|
|
98
|
-
| High | 6+ files | 5-10 tasks |
|
|
99
|
-
|
|
100
|
-
---
|
|
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
|
|
101
84
|
|
|
102
|
-
|
|
85
|
+
**Complexity Rules**:
|
|
86
|
+
| Complexity | Files | Tasks |
|
|
87
|
+
|------------|-------|-------|
|
|
88
|
+
| Low | 1-2 | 1-3 |
|
|
89
|
+
| Medium | 3-5 | 3-6 |
|
|
90
|
+
| High | 6+ | 5-10 |
|
|
103
91
|
|
|
104
|
-
|
|
92
|
+
#### Phase 2: ACE Exploration
|
|
105
93
|
|
|
94
|
+
**Primary**: ACE semantic search
|
|
106
95
|
```javascript
|
|
107
|
-
// For each issue, perform semantic search
|
|
108
96
|
mcp__ace-tool__search_context({
|
|
109
97
|
project_root_path: project_root,
|
|
110
|
-
query: `Find code related to: ${issue.title}.
|
|
98
|
+
query: `Find code related to: ${issue.title}. Keywords: ${extractKeywords(issue)}`
|
|
111
99
|
})
|
|
112
100
|
```
|
|
113
101
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
For each issue:
|
|
102
|
+
**Exploration Checklist**:
|
|
117
103
|
- [ ] Identify relevant files (direct matches)
|
|
118
|
-
- [ ] Find related patterns (
|
|
119
|
-
- [ ] Map integration points
|
|
120
|
-
- [ ] Discover dependencies
|
|
121
|
-
- [ ] Locate test patterns
|
|
104
|
+
- [ ] Find related patterns (similar implementations)
|
|
105
|
+
- [ ] Map integration points
|
|
106
|
+
- [ ] Discover dependencies
|
|
107
|
+
- [ ] Locate test patterns
|
|
122
108
|
|
|
123
|
-
|
|
109
|
+
**Fallback Chain**: ACE → smart_search → Grep → rg → Glob
|
|
124
110
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
mcp__ace-tool__search_context(
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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 |
|
|
131
118
|
|
|
132
|
-
|
|
133
|
-
mcp__ace-tool__search_context({
|
|
134
|
-
project_root_path: project_root,
|
|
135
|
-
query: "How are API routes protected? Find middleware patterns. Keywords: middleware, router, protect"
|
|
136
|
-
})
|
|
119
|
+
#### Phase 3: Solution Planning
|
|
137
120
|
|
|
138
|
-
|
|
139
|
-
mcp__ace-tool__search_context({
|
|
140
|
-
project_root_path: project_root,
|
|
141
|
-
query: "Where do I add new middleware to the Express app? Keywords: app.use, router.use, middleware"
|
|
142
|
-
})
|
|
121
|
+
**Multi-Solution Generation**:
|
|
143
122
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
})
|
|
149
|
-
```
|
|
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.)
|
|
150
127
|
|
|
151
|
-
|
|
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 |
|
|
152
133
|
|
|
134
|
+
**Solution Evaluation** (for each candidate):
|
|
153
135
|
```javascript
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
})),
|
|
162
|
-
modification_points: identifyModificationPoints(aceResults),
|
|
163
|
-
patterns: extractPatterns(aceResults),
|
|
164
|
-
dependencies: extractDependencies(aceResults),
|
|
165
|
-
test_patterns: findTestPatterns(aceResults),
|
|
166
|
-
risks: identifyRisks(aceResults)
|
|
167
|
-
}
|
|
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)
|
|
168
143
|
}
|
|
169
144
|
```
|
|
170
145
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
try {
|
|
177
|
-
return await mcp__ace-tool__search_context({
|
|
178
|
-
project_root_path: projectRoot,
|
|
179
|
-
query: buildQuery(issue)
|
|
180
|
-
})
|
|
181
|
-
} catch (error) {
|
|
182
|
-
console.warn('ACE search failed, falling back to ripgrep')
|
|
183
|
-
return await ripgrepFallback(issue, projectRoot)
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
async function ripgrepFallback(issue, projectRoot) {
|
|
188
|
-
const keywords = extractKeywords(issue)
|
|
189
|
-
const results = []
|
|
190
|
-
for (const keyword of keywords) {
|
|
191
|
-
const matches = Bash(`rg "${keyword}" --type ts --type js -l`)
|
|
192
|
-
results.push(...matches.split('\n').filter(Boolean))
|
|
193
|
-
}
|
|
194
|
-
return { files: [...new Set(results)] }
|
|
195
|
-
}
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
---
|
|
199
|
-
|
|
200
|
-
## Phase 3: Solution Planning
|
|
201
|
-
|
|
202
|
-
### Task Decomposition (Closed-Loop)
|
|
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
|
|
203
151
|
|
|
152
|
+
**Task Decomposition** following schema:
|
|
204
153
|
```javascript
|
|
205
154
|
function decomposeTasks(issue, exploration) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
acceptance: generateAcceptanceCriteria(group),
|
|
232
|
-
|
|
233
|
-
// Phase 5: Commit
|
|
234
|
-
commit: generateCommitSpec(group, issue),
|
|
235
|
-
|
|
236
|
-
depends_on: inferDependencies(group, tasks),
|
|
237
|
-
estimated_minutes: estimateTime(group),
|
|
238
|
-
executor: inferExecutor(group)
|
|
239
|
-
})
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return tasks
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
function generateTestRequirements(group, exploration, lifecycle) {
|
|
246
|
-
const test = {
|
|
247
|
-
unit: [],
|
|
248
|
-
integration: [],
|
|
249
|
-
commands: [],
|
|
250
|
-
coverage_target: 80
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Generate unit test requirements based on action
|
|
254
|
-
if (group.action === 'Create' || group.action === 'Implement') {
|
|
255
|
-
test.unit.push(`Test ${group.title} happy path`)
|
|
256
|
-
test.unit.push(`Test ${group.title} error cases`)
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Generate test commands based on project patterns
|
|
260
|
-
if (exploration.test_patterns?.includes('jest')) {
|
|
261
|
-
test.commands.push(`npm test -- --grep '${group.scope}'`)
|
|
262
|
-
} else if (exploration.test_patterns?.includes('vitest')) {
|
|
263
|
-
test.commands.push(`npx vitest run ${group.scope}`)
|
|
264
|
-
} else {
|
|
265
|
-
test.commands.push(`npm test`)
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// Add integration tests if needed
|
|
269
|
-
if (lifecycle?.test_strategy === 'integration' || lifecycle?.test_strategy === 'e2e') {
|
|
270
|
-
test.integration.push(`Integration test for ${group.title}`)
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
return test
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function generateRegressionChecks(group, lifecycle) {
|
|
277
|
-
const regression = []
|
|
278
|
-
|
|
279
|
-
switch (lifecycle?.regression_scope) {
|
|
280
|
-
case 'full':
|
|
281
|
-
regression.push('npm test')
|
|
282
|
-
regression.push('npm run test:integration')
|
|
283
|
-
break
|
|
284
|
-
case 'related':
|
|
285
|
-
regression.push(`npm test -- --grep '${group.scope}'`)
|
|
286
|
-
regression.push(`npm test -- --changed`)
|
|
287
|
-
break
|
|
288
|
-
case 'affected':
|
|
289
|
-
default:
|
|
290
|
-
regression.push(`npm test -- --findRelatedTests ${group.points[0]?.file}`)
|
|
291
|
-
break
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
return regression
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
function generateCommitSpec(group, issue) {
|
|
298
|
-
const typeMap = {
|
|
299
|
-
'Create': 'feat',
|
|
300
|
-
'Implement': 'feat',
|
|
301
|
-
'Update': 'feat',
|
|
302
|
-
'Fix': 'fix',
|
|
303
|
-
'Refactor': 'refactor',
|
|
304
|
-
'Test': 'test',
|
|
305
|
-
'Configure': 'chore',
|
|
306
|
-
'Delete': 'chore'
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
const scope = group.scope.split('/').pop()?.replace(/\..*$/, '') || 'core'
|
|
310
|
-
|
|
311
|
-
return {
|
|
312
|
-
type: typeMap[group.action] || 'feat',
|
|
313
|
-
scope: scope,
|
|
314
|
-
message_template: `${typeMap[group.action] || 'feat'}(${scope}): ${group.title.toLowerCase()}\n\n${group.description || ''}`,
|
|
315
|
-
breaking: false
|
|
316
|
-
}
|
|
155
|
+
return groups.map(group => ({
|
|
156
|
+
id: `T${taskId++}`, // Pattern: ^T[0-9]+$
|
|
157
|
+
title: group.title,
|
|
158
|
+
scope: inferScope(group), // Module path
|
|
159
|
+
action: inferAction(group), // Create | Update | Implement | ...
|
|
160
|
+
description: group.description,
|
|
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
|
+
},
|
|
176
|
+
depends_on: inferDependencies(group, tasks),
|
|
177
|
+
executor: inferExecutor(group),
|
|
178
|
+
priority: calculatePriority(group) // 1-5 (1=highest)
|
|
179
|
+
}))
|
|
317
180
|
}
|
|
318
181
|
```
|
|
319
182
|
|
|
320
|
-
|
|
183
|
+
#### Phase 4: Validation & Output
|
|
321
184
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
'create': 'Create',
|
|
327
|
-
'add': 'Implement',
|
|
328
|
-
'implement': 'Implement',
|
|
329
|
-
'modify': 'Update',
|
|
330
|
-
'update': 'Update',
|
|
331
|
-
'refactor': 'Refactor',
|
|
332
|
-
'config': 'Configure',
|
|
333
|
-
'test': 'Test',
|
|
334
|
-
'fix': 'Fix',
|
|
335
|
-
'remove': 'Delete',
|
|
336
|
-
'delete': 'Delete'
|
|
337
|
-
}
|
|
185
|
+
**Validation**:
|
|
186
|
+
- DAG validation (no circular dependencies)
|
|
187
|
+
- Task validation (all 5 phases present)
|
|
188
|
+
- Conflict detection (cross-issue file modifications)
|
|
338
189
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
return 'Implement'
|
|
345
|
-
}
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
### Dependency Analysis
|
|
349
|
-
|
|
350
|
-
```javascript
|
|
351
|
-
function inferDependencies(currentTask, existingTasks) {
|
|
352
|
-
const deps = []
|
|
353
|
-
|
|
354
|
-
// Rule 1: Update depends on Create for same file
|
|
355
|
-
for (const task of existingTasks) {
|
|
356
|
-
if (task.action === 'Create' && currentTask.action !== 'Create') {
|
|
357
|
-
const taskFiles = task.modification_points.map(mp => mp.file)
|
|
358
|
-
const currentFiles = currentTask.modification_points.map(mp => mp.file)
|
|
359
|
-
if (taskFiles.some(f => currentFiles.includes(f))) {
|
|
360
|
-
deps.push(task.id)
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// Rule 2: Test depends on implementation
|
|
366
|
-
if (currentTask.action === 'Test') {
|
|
367
|
-
const testTarget = currentTask.scope.replace(/__tests__|tests?|spec/gi, '')
|
|
368
|
-
for (const task of existingTasks) {
|
|
369
|
-
if (task.scope.includes(testTarget) && ['Create', 'Implement', 'Update'].includes(task.action)) {
|
|
370
|
-
deps.push(task.id)
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
return [...new Set(deps)]
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
function validateDAG(tasks) {
|
|
379
|
-
const graph = new Map(tasks.map(t => [t.id, t.depends_on || []]))
|
|
380
|
-
const visited = new Set()
|
|
381
|
-
const stack = new Set()
|
|
382
|
-
|
|
383
|
-
function hasCycle(taskId) {
|
|
384
|
-
if (stack.has(taskId)) return true
|
|
385
|
-
if (visited.has(taskId)) return false
|
|
386
|
-
|
|
387
|
-
visited.add(taskId)
|
|
388
|
-
stack.add(taskId)
|
|
389
|
-
|
|
390
|
-
for (const dep of graph.get(taskId) || []) {
|
|
391
|
-
if (hasCycle(dep)) return true
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
stack.delete(taskId)
|
|
395
|
-
return false
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
for (const taskId of graph.keys()) {
|
|
399
|
-
if (hasCycle(taskId)) {
|
|
400
|
-
return { valid: false, error: `Circular dependency detected involving ${taskId}` }
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
return { valid: true }
|
|
405
|
-
}
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
### Implementation Steps Generation
|
|
409
|
-
|
|
410
|
-
```javascript
|
|
411
|
-
function generateImplementationSteps(group, exploration) {
|
|
412
|
-
const steps = []
|
|
413
|
-
|
|
414
|
-
// Step 1: Setup/Preparation
|
|
415
|
-
if (group.action === 'Create') {
|
|
416
|
-
steps.push(`Create ${group.scope} file structure`)
|
|
417
|
-
} else {
|
|
418
|
-
steps.push(`Locate ${group.points[0].target} in ${group.points[0].file}`)
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
// Step 2-N: Core implementation based on patterns
|
|
422
|
-
if (exploration.patterns) {
|
|
423
|
-
steps.push(`Follow pattern: ${exploration.patterns}`)
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
// Add modification-specific steps
|
|
427
|
-
for (const point of group.points) {
|
|
428
|
-
steps.push(`${point.change} at ${point.target}`)
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
// Final step: Integration
|
|
432
|
-
steps.push('Add error handling and edge cases')
|
|
433
|
-
steps.push('Update imports and exports as needed')
|
|
434
|
-
|
|
435
|
-
return steps.slice(0, 7) // Max 7 steps
|
|
436
|
-
}
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
### Acceptance Criteria Generation (Closed-Loop)
|
|
440
|
-
|
|
441
|
-
```javascript
|
|
442
|
-
function generateAcceptanceCriteria(task) {
|
|
443
|
-
const acceptance = {
|
|
444
|
-
criteria: [],
|
|
445
|
-
verification: [],
|
|
446
|
-
manual_checks: []
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
// Action-specific criteria
|
|
450
|
-
const actionCriteria = {
|
|
451
|
-
'Create': [`${task.scope} file created and exports correctly`],
|
|
452
|
-
'Implement': [`Feature ${task.title} works as specified`],
|
|
453
|
-
'Update': [`Modified behavior matches requirements`],
|
|
454
|
-
'Test': [`All test cases pass`, `Coverage >= 80%`],
|
|
455
|
-
'Fix': [`Bug no longer reproducible`],
|
|
456
|
-
'Configure': [`Configuration applied correctly`]
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
acceptance.criteria.push(...(actionCriteria[task.action] || []))
|
|
460
|
-
|
|
461
|
-
// Add quantified criteria
|
|
462
|
-
if (task.modification_points.length > 0) {
|
|
463
|
-
acceptance.criteria.push(`${task.modification_points.length} file(s) modified correctly`)
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// Generate verification steps for each criterion
|
|
467
|
-
for (const criterion of acceptance.criteria) {
|
|
468
|
-
acceptance.verification.push(generateVerificationStep(criterion, task))
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// Limit to reasonable counts
|
|
472
|
-
acceptance.criteria = acceptance.criteria.slice(0, 4)
|
|
473
|
-
acceptance.verification = acceptance.verification.slice(0, 4)
|
|
474
|
-
|
|
475
|
-
return acceptance
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
function generateVerificationStep(criterion, task) {
|
|
479
|
-
// Generate executable verification for criterion
|
|
480
|
-
if (criterion.includes('file created')) {
|
|
481
|
-
return `ls -la ${task.modification_points[0]?.file} && head -20 ${task.modification_points[0]?.file}`
|
|
482
|
-
}
|
|
483
|
-
if (criterion.includes('test')) {
|
|
484
|
-
return `npm test -- --grep '${task.scope}'`
|
|
485
|
-
}
|
|
486
|
-
if (criterion.includes('export')) {
|
|
487
|
-
return `node -e "console.log(require('./${task.modification_points[0]?.file}'))"`
|
|
488
|
-
}
|
|
489
|
-
if (criterion.includes('API') || criterion.includes('endpoint')) {
|
|
490
|
-
return `curl -X GET http://localhost:3000/${task.scope} -v`
|
|
491
|
-
}
|
|
492
|
-
// Default: describe manual check
|
|
493
|
-
return `Manually verify: ${criterion}`
|
|
494
|
-
}
|
|
190
|
+
**Solution Registration**:
|
|
191
|
+
```bash
|
|
192
|
+
# Write solution and register via CLI
|
|
193
|
+
ccw issue bind <issue-id> --solution /tmp/sol.json
|
|
495
194
|
```
|
|
496
195
|
|
|
497
196
|
---
|
|
498
197
|
|
|
499
|
-
##
|
|
500
|
-
|
|
501
|
-
### Solution Validation
|
|
502
|
-
|
|
503
|
-
```javascript
|
|
504
|
-
function validateSolution(solution) {
|
|
505
|
-
const errors = []
|
|
506
|
-
|
|
507
|
-
// Validate tasks
|
|
508
|
-
for (const task of solution.tasks) {
|
|
509
|
-
const taskErrors = validateTask(task)
|
|
510
|
-
if (taskErrors.length > 0) {
|
|
511
|
-
errors.push(...taskErrors.map(e => `${task.id}: ${e}`))
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
// Validate DAG
|
|
516
|
-
const dagResult = validateDAG(solution.tasks)
|
|
517
|
-
if (!dagResult.valid) {
|
|
518
|
-
errors.push(dagResult.error)
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// Validate modification points exist
|
|
522
|
-
for (const task of solution.tasks) {
|
|
523
|
-
for (const mp of task.modification_points) {
|
|
524
|
-
if (mp.target !== 'new file' && !fileExists(mp.file)) {
|
|
525
|
-
errors.push(`${task.id}: File not found: ${mp.file}`)
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
return { valid: errors.length === 0, errors }
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
function validateTask(task) {
|
|
534
|
-
const errors = []
|
|
535
|
-
|
|
536
|
-
// Basic fields
|
|
537
|
-
if (!/^T\d+$/.test(task.id)) errors.push('Invalid task ID format')
|
|
538
|
-
if (!task.title?.trim()) errors.push('Missing title')
|
|
539
|
-
if (!task.scope?.trim()) errors.push('Missing scope')
|
|
540
|
-
if (!['Create', 'Update', 'Implement', 'Refactor', 'Configure', 'Test', 'Fix', 'Delete'].includes(task.action)) {
|
|
541
|
-
errors.push('Invalid action type')
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
// Phase 1: Implementation
|
|
545
|
-
if (!task.implementation || task.implementation.length < 2) {
|
|
546
|
-
errors.push('Need 2+ implementation steps')
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
// Phase 2: Test
|
|
550
|
-
if (!task.test) {
|
|
551
|
-
errors.push('Missing test phase')
|
|
552
|
-
} else {
|
|
553
|
-
if (!task.test.commands || task.test.commands.length < 1) {
|
|
554
|
-
errors.push('Need 1+ test commands')
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
// Phase 3: Regression
|
|
559
|
-
if (!task.regression || task.regression.length < 1) {
|
|
560
|
-
errors.push('Need 1+ regression checks')
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
// Phase 4: Acceptance
|
|
564
|
-
if (!task.acceptance) {
|
|
565
|
-
errors.push('Missing acceptance phase')
|
|
566
|
-
} else {
|
|
567
|
-
if (!task.acceptance.criteria || task.acceptance.criteria.length < 1) {
|
|
568
|
-
errors.push('Need 1+ acceptance criteria')
|
|
569
|
-
}
|
|
570
|
-
if (!task.acceptance.verification || task.acceptance.verification.length < 1) {
|
|
571
|
-
errors.push('Need 1+ verification steps')
|
|
572
|
-
}
|
|
573
|
-
if (task.acceptance.criteria?.some(a => /works correctly|good performance|properly/i.test(a))) {
|
|
574
|
-
errors.push('Vague acceptance criteria')
|
|
575
|
-
}
|
|
576
|
-
}
|
|
198
|
+
## 2. Output Requirements
|
|
577
199
|
|
|
578
|
-
|
|
579
|
-
if (!task.commit) {
|
|
580
|
-
errors.push('Missing commit phase')
|
|
581
|
-
} else {
|
|
582
|
-
if (!['feat', 'fix', 'refactor', 'test', 'docs', 'chore'].includes(task.commit.type)) {
|
|
583
|
-
errors.push('Invalid commit type')
|
|
584
|
-
}
|
|
585
|
-
if (!task.commit.scope?.trim()) {
|
|
586
|
-
errors.push('Missing commit scope')
|
|
587
|
-
}
|
|
588
|
-
if (!task.commit.message_template?.trim()) {
|
|
589
|
-
errors.push('Missing commit message template')
|
|
590
|
-
}
|
|
591
|
-
}
|
|
200
|
+
### 2.1 Generate Files (Primary)
|
|
592
201
|
|
|
593
|
-
|
|
594
|
-
}
|
|
202
|
+
**Solution file per issue**:
|
|
595
203
|
```
|
|
596
|
-
|
|
597
|
-
### Conflict Detection (Batch Mode)
|
|
598
|
-
|
|
599
|
-
```javascript
|
|
600
|
-
function detectConflicts(solutions) {
|
|
601
|
-
const fileModifications = new Map() // file -> [issue_ids]
|
|
602
|
-
|
|
603
|
-
for (const solution of solutions) {
|
|
604
|
-
for (const task of solution.tasks) {
|
|
605
|
-
for (const mp of task.modification_points) {
|
|
606
|
-
if (!fileModifications.has(mp.file)) {
|
|
607
|
-
fileModifications.set(mp.file, [])
|
|
608
|
-
}
|
|
609
|
-
if (!fileModifications.get(mp.file).includes(solution.issue_id)) {
|
|
610
|
-
fileModifications.get(mp.file).push(solution.issue_id)
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
const conflicts = []
|
|
617
|
-
for (const [file, issues] of fileModifications) {
|
|
618
|
-
if (issues.length > 1) {
|
|
619
|
-
conflicts.push({
|
|
620
|
-
file,
|
|
621
|
-
issues,
|
|
622
|
-
suggested_order: suggestOrder(issues, solutions)
|
|
623
|
-
})
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
return conflicts
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
function suggestOrder(issueIds, solutions) {
|
|
631
|
-
// Order by: Create before Update, foundation before integration
|
|
632
|
-
return issueIds.sort((a, b) => {
|
|
633
|
-
const solA = solutions.find(s => s.issue_id === a)
|
|
634
|
-
const solB = solutions.find(s => s.issue_id === b)
|
|
635
|
-
const hasCreateA = solA.tasks.some(t => t.action === 'Create')
|
|
636
|
-
const hasCreateB = solB.tasks.some(t => t.action === 'Create')
|
|
637
|
-
if (hasCreateA && !hasCreateB) return -1
|
|
638
|
-
if (hasCreateB && !hasCreateA) return 1
|
|
639
|
-
return 0
|
|
640
|
-
})
|
|
641
|
-
}
|
|
204
|
+
.workflow/issues/solutions/{issue-id}.jsonl
|
|
642
205
|
```
|
|
643
206
|
|
|
644
|
-
|
|
207
|
+
Each line is a solution JSON containing tasks. Schema: `cat .claude/workflows/cli-templates/schemas/solution-schema.json`
|
|
645
208
|
|
|
646
|
-
|
|
647
|
-
function generateOutput(solutions, conflicts) {
|
|
648
|
-
return {
|
|
649
|
-
solutions: solutions.map(s => ({
|
|
650
|
-
issue_id: s.issue_id,
|
|
651
|
-
solution: s
|
|
652
|
-
})),
|
|
653
|
-
conflicts,
|
|
654
|
-
_metadata: {
|
|
655
|
-
timestamp: new Date().toISOString(),
|
|
656
|
-
source: 'issue-plan-agent',
|
|
657
|
-
issues_count: solutions.length,
|
|
658
|
-
total_tasks: solutions.reduce((sum, s) => sum + s.tasks.length, 0)
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
```
|
|
209
|
+
### 2.2 Binding
|
|
663
210
|
|
|
664
|
-
|
|
211
|
+
| Scenario | Action |
|
|
212
|
+
|----------|--------|
|
|
213
|
+
| Single solution | `ccw issue bind <id> --solution <file>` (auto) |
|
|
214
|
+
| Multiple solutions | Register only, return for selection |
|
|
665
215
|
|
|
666
|
-
|
|
216
|
+
### 2.3 Return Summary
|
|
667
217
|
|
|
668
218
|
```json
|
|
669
219
|
{
|
|
670
|
-
"issue_id": "
|
|
671
|
-
"
|
|
672
|
-
"
|
|
673
|
-
"tasks": [
|
|
674
|
-
{
|
|
675
|
-
"id": "T1",
|
|
676
|
-
"title": "Create JWT validation middleware",
|
|
677
|
-
"scope": "src/middleware/",
|
|
678
|
-
"action": "Create",
|
|
679
|
-
"description": "Create middleware to validate JWT tokens",
|
|
680
|
-
"modification_points": [
|
|
681
|
-
{ "file": "src/middleware/auth.ts", "target": "new file", "change": "Create middleware" }
|
|
682
|
-
],
|
|
683
|
-
|
|
684
|
-
"implementation": [
|
|
685
|
-
"Create auth.ts file in src/middleware/",
|
|
686
|
-
"Implement JWT token extraction from Authorization header",
|
|
687
|
-
"Add token validation using jsonwebtoken library",
|
|
688
|
-
"Handle error cases (missing, invalid, expired tokens)",
|
|
689
|
-
"Export middleware function"
|
|
690
|
-
],
|
|
691
|
-
|
|
692
|
-
"test": {
|
|
693
|
-
"unit": [
|
|
694
|
-
"Test valid token passes through",
|
|
695
|
-
"Test invalid token returns 401",
|
|
696
|
-
"Test expired token returns 401",
|
|
697
|
-
"Test missing token returns 401"
|
|
698
|
-
],
|
|
699
|
-
"integration": [
|
|
700
|
-
"Protected route returns 401 without token",
|
|
701
|
-
"Protected route returns 200 with valid token"
|
|
702
|
-
],
|
|
703
|
-
"commands": [
|
|
704
|
-
"npm test -- --grep 'auth middleware'",
|
|
705
|
-
"npm run test:coverage -- src/middleware/auth.ts"
|
|
706
|
-
],
|
|
707
|
-
"coverage_target": 80
|
|
708
|
-
},
|
|
709
|
-
|
|
710
|
-
"regression": [
|
|
711
|
-
"npm test -- --grep 'existing routes'",
|
|
712
|
-
"npm run test:integration"
|
|
713
|
-
],
|
|
714
|
-
|
|
715
|
-
"acceptance": {
|
|
716
|
-
"criteria": [
|
|
717
|
-
"Middleware validates JWT tokens successfully",
|
|
718
|
-
"Returns 401 with appropriate error for invalid tokens",
|
|
719
|
-
"Passes decoded user payload to request context"
|
|
720
|
-
],
|
|
721
|
-
"verification": [
|
|
722
|
-
"curl -H 'Authorization: Bearer <valid>' /api/protected → 200",
|
|
723
|
-
"curl /api/protected → 401 {error: 'No token'}",
|
|
724
|
-
"curl -H 'Authorization: Bearer invalid' /api/protected → 401"
|
|
725
|
-
],
|
|
726
|
-
"manual_checks": []
|
|
727
|
-
},
|
|
728
|
-
|
|
729
|
-
"commit": {
|
|
730
|
-
"type": "feat",
|
|
731
|
-
"scope": "auth",
|
|
732
|
-
"message_template": "feat(auth): add JWT validation middleware\n\n- Implement token extraction and validation\n- Add error handling for invalid/expired tokens\n- Export middleware for route protection",
|
|
733
|
-
"breaking": false
|
|
734
|
-
},
|
|
735
|
-
|
|
736
|
-
"depends_on": [],
|
|
737
|
-
"estimated_minutes": 30,
|
|
738
|
-
"executor": "codex"
|
|
739
|
-
}
|
|
740
|
-
],
|
|
741
|
-
"exploration_context": {
|
|
742
|
-
"relevant_files": ["src/config/env.ts"],
|
|
743
|
-
"patterns": "Follow existing middleware pattern",
|
|
744
|
-
"test_patterns": "Jest + supertest"
|
|
745
|
-
},
|
|
746
|
-
"estimated_total_minutes": 70,
|
|
747
|
-
"complexity": "Medium"
|
|
748
|
-
}
|
|
749
|
-
```
|
|
750
|
-
|
|
751
|
-
---
|
|
752
|
-
|
|
753
|
-
## Error Handling
|
|
754
|
-
|
|
755
|
-
```javascript
|
|
756
|
-
// Error handling with fallback
|
|
757
|
-
async function executeWithFallback(issue, projectRoot) {
|
|
758
|
-
try {
|
|
759
|
-
// Primary: ACE semantic search
|
|
760
|
-
const exploration = await aceExplore(issue, projectRoot)
|
|
761
|
-
return await generateSolution(issue, exploration)
|
|
762
|
-
} catch (aceError) {
|
|
763
|
-
console.warn('ACE failed:', aceError.message)
|
|
764
|
-
|
|
765
|
-
try {
|
|
766
|
-
// Fallback: ripgrep-based exploration
|
|
767
|
-
const exploration = await ripgrepExplore(issue, projectRoot)
|
|
768
|
-
return await generateSolution(issue, exploration)
|
|
769
|
-
} catch (rgError) {
|
|
770
|
-
// Degraded: Basic solution without exploration
|
|
771
|
-
return {
|
|
772
|
-
issue_id: issue.id,
|
|
773
|
-
approach_name: 'Basic Implementation',
|
|
774
|
-
summary: issue.title,
|
|
775
|
-
tasks: [{
|
|
776
|
-
id: 'T1',
|
|
777
|
-
title: issue.title,
|
|
778
|
-
scope: 'TBD',
|
|
779
|
-
action: 'Implement',
|
|
780
|
-
description: issue.description,
|
|
781
|
-
modification_points: [{ file: 'TBD', target: 'TBD', change: issue.title }],
|
|
782
|
-
implementation: ['Analyze requirements', 'Implement solution', 'Test and validate'],
|
|
783
|
-
acceptance: ['Feature works as described'],
|
|
784
|
-
depends_on: [],
|
|
785
|
-
estimated_minutes: 60
|
|
786
|
-
}],
|
|
787
|
-
exploration_context: { relevant_files: [], patterns: 'Manual exploration required' },
|
|
788
|
-
estimated_total_minutes: 60,
|
|
789
|
-
complexity: 'Medium',
|
|
790
|
-
_warning: 'Degraded mode - manual exploration required'
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
}
|
|
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": [...] }]
|
|
794
223
|
}
|
|
795
224
|
```
|
|
796
225
|
|
|
797
|
-
| Scenario | Action |
|
|
798
|
-
|----------|--------|
|
|
799
|
-
| ACE search returns no results | Fallback to ripgrep, warn user |
|
|
800
|
-
| Circular task dependency | Report error, suggest fix |
|
|
801
|
-
| File not found in codebase | Flag as "new file", update modification_points |
|
|
802
|
-
| Ambiguous requirements | Add clarification_needs to output |
|
|
803
|
-
|
|
804
226
|
---
|
|
805
227
|
|
|
806
|
-
## Quality Standards
|
|
228
|
+
## 3. Quality Standards
|
|
807
229
|
|
|
808
|
-
### Acceptance Criteria
|
|
230
|
+
### 3.1 Acceptance Criteria
|
|
809
231
|
|
|
810
232
|
| Good | Bad |
|
|
811
233
|
|------|-----|
|
|
812
234
|
| "3 API endpoints: GET, POST, DELETE" | "API works correctly" |
|
|
813
235
|
| "Response time < 200ms p95" | "Good performance" |
|
|
814
236
|
| "All 4 test cases pass" | "Tests pass" |
|
|
815
|
-
| "JWT token validated with secret from env" | "Authentication works" |
|
|
816
237
|
|
|
817
|
-
###
|
|
238
|
+
### 3.2 Validation Checklist
|
|
818
239
|
|
|
819
|
-
Before outputting solution:
|
|
820
240
|
- [ ] ACE search performed for each issue
|
|
821
241
|
- [ ] All modification_points verified against codebase
|
|
822
242
|
- [ ] Tasks have 2+ implementation steps
|
|
823
|
-
- [ ]
|
|
824
|
-
- [ ]
|
|
825
|
-
- [ ]
|
|
826
|
-
|
|
827
|
-
---
|
|
243
|
+
- [ ] All 5 lifecycle phases present
|
|
244
|
+
- [ ] Quantified acceptance criteria with verification
|
|
245
|
+
- [ ] Dependencies form valid DAG
|
|
246
|
+
- [ ] Commit follows conventional commits
|
|
828
247
|
|
|
829
|
-
|
|
248
|
+
### 3.3 Guidelines
|
|
830
249
|
|
|
831
250
|
**ALWAYS**:
|
|
832
|
-
1.
|
|
833
|
-
2.
|
|
834
|
-
3.
|
|
835
|
-
4. Quantify acceptance
|
|
836
|
-
5. Validate DAG before output
|
|
837
|
-
6.
|
|
838
|
-
7.
|
|
839
|
-
8.
|
|
840
|
-
9. **Generate ALL 5 lifecycle phases for each task**:
|
|
841
|
-
- `implementation`: 2-7 concrete steps
|
|
842
|
-
- `test`: unit tests, commands, coverage target
|
|
843
|
-
- `regression`: regression check commands
|
|
844
|
-
- `acceptance`: criteria + verification steps
|
|
845
|
-
- `commit`: type, scope, message template
|
|
846
|
-
10. Infer test commands from project's test framework
|
|
847
|
-
11. Generate commit message following conventional commits
|
|
251
|
+
1. Read schema first: `cat .claude/workflows/cli-templates/schemas/solution-schema.json`
|
|
252
|
+
2. Use ACE semantic search as PRIMARY exploration tool
|
|
253
|
+
3. Fetch issue details via `ccw issue status <id> --json`
|
|
254
|
+
4. Quantify acceptance.criteria with testable conditions
|
|
255
|
+
5. Validate DAG before output
|
|
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
|
|
848
259
|
|
|
849
260
|
**NEVER**:
|
|
850
261
|
1. Execute implementation (return plan only)
|
|
851
|
-
2. Use vague
|
|
852
|
-
3. Create circular dependencies
|
|
853
|
-
4.
|
|
854
|
-
5.
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
262
|
+
2. Use vague criteria ("works correctly", "good performance")
|
|
263
|
+
3. Create circular dependencies
|
|
264
|
+
4. Generate more than 10 tasks per issue
|
|
265
|
+
5. Bind when multiple solutions exist
|
|
266
|
+
|
|
267
|
+
**OUTPUT**:
|
|
268
|
+
1. Register solutions via `ccw issue bind <id> --solution <file>`
|
|
269
|
+
2. Return JSON with `bound`, `pending_selection`, `conflicts`
|
|
270
|
+
3. Solutions written to `.workflow/issues/solutions/{issue-id}.jsonl`
|