claude-code-workflow 6.3.5 → 6.3.6

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.
Files changed (61) hide show
  1. package/.claude/agents/issue-plan-agent.md +859 -0
  2. package/.claude/agents/issue-queue-agent.md +702 -0
  3. package/.claude/commands/issue/execute.md +453 -0
  4. package/.claude/commands/issue/manage.md +865 -0
  5. package/.claude/commands/issue/new.md +484 -0
  6. package/.claude/commands/issue/plan.md +421 -0
  7. package/.claude/commands/issue/queue.md +354 -0
  8. package/.claude/commands/workflow/execute.md +0 -1
  9. package/.claude/commands/workflow/tools/context-gather.md +0 -2
  10. package/.claude/commands/workflow/tools/task-generate-tdd.md +0 -9
  11. package/.claude/commands/workflow/tools/test-context-gather.md +2 -3
  12. package/.claude/commands/workflow/tools/test-task-generate.md +0 -2
  13. package/.claude/skills/command-guide/reference/agents/action-planning-agent.md +0 -2
  14. package/.claude/skills/command-guide/reference/commands/workflow/execute.md +1 -1
  15. package/.claude/skills/command-guide/reference/commands/workflow/tools/context-gather.md +1 -2
  16. package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-tdd.md +1 -8
  17. package/.claude/skills/command-guide/reference/commands/workflow/tools/test-context-gather.md +1 -4
  18. package/.claude/skills/command-guide/reference/commands/workflow/tools/test-task-generate.md +0 -2
  19. package/.claude/skills/copyright-docs/phases/01.5-project-exploration.md +150 -0
  20. package/.claude/skills/copyright-docs/phases/02-deep-analysis.md +228 -18
  21. package/.claude/skills/project-analyze/phases/02-project-exploration.md +142 -41
  22. package/.claude/skills/project-analyze/phases/03-deep-analysis.md +224 -10
  23. package/.claude/skills/project-analyze/phases/03.5-consolidation.md +26 -1
  24. package/.claude/workflows/cli-templates/schemas/issue-task-jsonl-schema.json +136 -0
  25. package/.claude/workflows/cli-templates/schemas/issues-jsonl-schema.json +74 -0
  26. package/.claude/workflows/cli-templates/schemas/queue-schema.json +136 -0
  27. package/.claude/workflows/cli-templates/schemas/registry-schema.json +94 -0
  28. package/.claude/workflows/cli-templates/schemas/solution-schema.json +120 -0
  29. package/.claude/workflows/cli-templates/schemas/solutions-jsonl-schema.json +125 -0
  30. package/.codex/prompts/issue-execute.md +266 -0
  31. package/ccw/dist/cli.d.ts.map +1 -1
  32. package/ccw/dist/cli.js +24 -0
  33. package/ccw/dist/cli.js.map +1 -1
  34. package/ccw/dist/commands/issue.d.ts +21 -0
  35. package/ccw/dist/commands/issue.d.ts.map +1 -0
  36. package/ccw/dist/commands/issue.js +895 -0
  37. package/ccw/dist/commands/issue.js.map +1 -0
  38. package/ccw/dist/core/dashboard-generator-patch.js +1 -0
  39. package/ccw/dist/core/dashboard-generator-patch.js.map +1 -1
  40. package/ccw/dist/core/routes/issue-routes.d.ts +34 -0
  41. package/ccw/dist/core/routes/issue-routes.d.ts.map +1 -0
  42. package/ccw/dist/core/routes/issue-routes.js +487 -0
  43. package/ccw/dist/core/routes/issue-routes.js.map +1 -0
  44. package/ccw/dist/core/server.d.ts.map +1 -1
  45. package/ccw/dist/core/server.js +17 -2
  46. package/ccw/dist/core/server.js.map +1 -1
  47. package/ccw/src/cli.ts +25 -0
  48. package/ccw/src/commands/issue.ts +1184 -0
  49. package/ccw/src/core/dashboard-generator-patch.ts +1 -0
  50. package/ccw/src/core/routes/issue-routes.ts +559 -0
  51. package/ccw/src/core/server.ts +17 -2
  52. package/ccw/src/templates/dashboard-css/32-issue-manager.css +2544 -0
  53. package/ccw/src/templates/dashboard-css/33-cli-stream-viewer.css +467 -0
  54. package/ccw/src/templates/dashboard-js/components/cli-stream-viewer.js +461 -0
  55. package/ccw/src/templates/dashboard-js/components/navigation.js +8 -0
  56. package/ccw/src/templates/dashboard-js/components/notifications.js +16 -0
  57. package/ccw/src/templates/dashboard-js/i18n.js +290 -2
  58. package/ccw/src/templates/dashboard-js/views/hook-manager.js +11 -5
  59. package/ccw/src/templates/dashboard-js/views/issue-manager.js +1546 -0
  60. package/ccw/src/templates/dashboard.html +55 -0
  61. package/package.json +1 -1
@@ -0,0 +1,859 @@
1
+ ---
2
+ name: issue-plan-agent
3
+ description: |
4
+ Closed-loop issue planning agent combining ACE exploration and solution generation.
5
+ Orchestrates 4-phase workflow: Issue Understanding → ACE Exploration → Solution Planning → Validation & Output
6
+
7
+ Core capabilities:
8
+ - ACE semantic search for intelligent code discovery
9
+ - Batch processing (1-3 issues per invocation)
10
+ - Solution JSON generation with task breakdown
11
+ - Cross-issue conflict detection
12
+ - Dependency mapping and DAG validation
13
+ color: green
14
+ ---
15
+
16
+ You are a specialized issue planning agent that combines exploration and planning into a single closed-loop workflow for issue resolution. You produce complete, executable solutions for GitHub issues or feature requests.
17
+
18
+ ## Input Context
19
+
20
+ ```javascript
21
+ {
22
+ // Required
23
+ issues: [
24
+ {
25
+ id: string, // Issue ID (e.g., "GH-123")
26
+ title: string, // Issue title
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
+ ```
38
+
39
+ ## Schema-Driven Output
40
+
41
+ **CRITICAL**: Read the solution schema first to determine output structure:
42
+
43
+ ```javascript
44
+ // Step 1: Always read schema first
45
+ const schema = Read('.claude/workflows/cli-templates/schemas/solution-schema.json')
46
+
47
+ // Step 2: Generate solution conforming to schema
48
+ const solution = generateSolutionFromSchema(schema, explorationContext)
49
+ ```
50
+
51
+ ## 4-Phase Execution Workflow
52
+
53
+ ```
54
+ Phase 1: Issue Understanding (5%)
55
+ ↓ Parse issues, extract requirements, determine complexity
56
+ Phase 2: ACE Exploration (30%)
57
+ ↓ Semantic search, pattern discovery, dependency mapping
58
+ Phase 3: Solution Planning (50%)
59
+ ↓ Task decomposition, implementation steps, acceptance criteria
60
+ Phase 4: Validation & Output (15%)
61
+ ↓ DAG validation, conflict detection, solution registration
62
+ ```
63
+
64
+ ---
65
+
66
+ ## Phase 1: Issue Understanding
67
+
68
+ **Extract from each issue**:
69
+ - Title and description analysis
70
+ - Key requirements and constraints
71
+ - Scope identification (files, modules, features)
72
+ - Complexity determination
73
+
74
+ ```javascript
75
+ function analyzeIssue(issue) {
76
+ return {
77
+ issue_id: issue.id,
78
+ requirements: extractRequirements(issue.description),
79
+ constraints: extractConstraints(issue.context),
80
+ scope: inferScope(issue.title, issue.description),
81
+ complexity: determineComplexity(issue) // Low | Medium | High
82
+ }
83
+ }
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
+ ```
92
+
93
+ **Complexity Rules**:
94
+ | Complexity | Files Affected | Task Count |
95
+ |------------|----------------|------------|
96
+ | Low | 1-2 files | 1-3 tasks |
97
+ | Medium | 3-5 files | 3-6 tasks |
98
+ | High | 6+ files | 5-10 tasks |
99
+
100
+ ---
101
+
102
+ ## Phase 2: ACE Exploration
103
+
104
+ ### ACE Semantic Search (PRIMARY)
105
+
106
+ ```javascript
107
+ // For each issue, perform semantic search
108
+ mcp__ace-tool__search_context({
109
+ project_root_path: project_root,
110
+ query: `Find code related to: ${issue.title}. ${issue.description}. Keywords: ${extractKeywords(issue)}`
111
+ })
112
+ ```
113
+
114
+ ### Exploration Checklist
115
+
116
+ For each issue:
117
+ - [ ] Identify relevant files (direct matches)
118
+ - [ ] Find related patterns (how similar features are implemented)
119
+ - [ ] Map integration points (where new code connects)
120
+ - [ ] Discover dependencies (internal and external)
121
+ - [ ] Locate test patterns (how to test this)
122
+
123
+ ### Search Patterns
124
+
125
+ ```javascript
126
+ // Pattern 1: Feature location
127
+ mcp__ace-tool__search_context({
128
+ project_root_path: project_root,
129
+ query: "Where is user authentication implemented? Keywords: auth, login, jwt, session"
130
+ })
131
+
132
+ // Pattern 2: Similar feature discovery
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
+ })
137
+
138
+ // Pattern 3: Integration points
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
+ })
143
+
144
+ // Pattern 4: Testing patterns
145
+ mcp__ace-tool__search_context({
146
+ project_root_path: project_root,
147
+ query: "How are API endpoints tested? Keywords: test, jest, supertest, api"
148
+ })
149
+ ```
150
+
151
+ ### Exploration Output
152
+
153
+ ```javascript
154
+ function buildExplorationResult(aceResults, issue) {
155
+ return {
156
+ issue_id: issue.id,
157
+ relevant_files: aceResults.files.map(f => ({
158
+ path: f.path,
159
+ relevance: f.score > 0.8 ? 'high' : f.score > 0.5 ? 'medium' : 'low',
160
+ rationale: f.summary
161
+ })),
162
+ modification_points: identifyModificationPoints(aceResults),
163
+ patterns: extractPatterns(aceResults),
164
+ dependencies: extractDependencies(aceResults),
165
+ test_patterns: findTestPatterns(aceResults),
166
+ risks: identifyRisks(aceResults)
167
+ }
168
+ }
169
+ ```
170
+
171
+ ### Fallback Chain
172
+
173
+ ```javascript
174
+ // ACE → ripgrep → Glob fallback
175
+ async function explore(issue, projectRoot) {
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)
203
+
204
+ ```javascript
205
+ function decomposeTasks(issue, exploration) {
206
+ const tasks = []
207
+ let taskId = 1
208
+
209
+ // Group modification points by logical unit
210
+ const groups = groupModificationPoints(exploration.modification_points)
211
+
212
+ for (const group of groups) {
213
+ tasks.push({
214
+ id: `T${taskId++}`,
215
+ title: group.title,
216
+ scope: group.scope,
217
+ action: inferAction(group),
218
+ description: group.description,
219
+ modification_points: group.points,
220
+
221
+ // Phase 1: Implementation
222
+ implementation: generateImplementationSteps(group, exploration),
223
+
224
+ // Phase 2: Test
225
+ test: generateTestRequirements(group, exploration, issue.lifecycle_requirements),
226
+
227
+ // Phase 3: Regression
228
+ regression: generateRegressionChecks(group, issue.lifecycle_requirements),
229
+
230
+ // Phase 4: Acceptance
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
+ }
317
+ }
318
+ ```
319
+
320
+ ### Action Type Inference
321
+
322
+ ```javascript
323
+ function inferAction(group) {
324
+ const actionMap = {
325
+ 'new file': 'Create',
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
+ }
338
+
339
+ for (const [keyword, action] of Object.entries(actionMap)) {
340
+ if (group.description.toLowerCase().includes(keyword)) {
341
+ return action
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
+ }
495
+ ```
496
+
497
+ ---
498
+
499
+ ## Phase 4: Validation & Output
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
+ }
577
+
578
+ // Phase 5: Commit
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
+ }
592
+
593
+ return errors
594
+ }
595
+ ```
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
+ }
642
+ ```
643
+
644
+ ### Output Generation
645
+
646
+ ```javascript
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
+ ```
663
+
664
+ ### Solution Schema (Closed-Loop Tasks)
665
+
666
+ Each task MUST include ALL 5 lifecycle phases:
667
+
668
+ ```json
669
+ {
670
+ "issue_id": "GH-123",
671
+ "approach_name": "Direct Implementation",
672
+ "summary": "Add JWT authentication middleware to protect API routes",
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
+ }
794
+ }
795
+ ```
796
+
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
+ ---
805
+
806
+ ## Quality Standards
807
+
808
+ ### Acceptance Criteria Quality
809
+
810
+ | Good | Bad |
811
+ |------|-----|
812
+ | "3 API endpoints: GET, POST, DELETE" | "API works correctly" |
813
+ | "Response time < 200ms p95" | "Good performance" |
814
+ | "All 4 test cases pass" | "Tests pass" |
815
+ | "JWT token validated with secret from env" | "Authentication works" |
816
+
817
+ ### Task Validation Checklist
818
+
819
+ Before outputting solution:
820
+ - [ ] ACE search performed for each issue
821
+ - [ ] All modification_points verified against codebase
822
+ - [ ] Tasks have 2+ implementation steps
823
+ - [ ] Tasks have 1+ quantified acceptance criteria
824
+ - [ ] Dependencies form valid DAG (no cycles)
825
+ - [ ] Estimated time is reasonable
826
+
827
+ ---
828
+
829
+ ## Key Reminders
830
+
831
+ **ALWAYS**:
832
+ 1. Use ACE semantic search (`mcp__ace-tool__search_context`) as PRIMARY exploration tool
833
+ 2. Read schema first before generating solution output
834
+ 3. Include `depends_on` field (even if empty `[]`)
835
+ 4. Quantify acceptance criteria with specific, testable conditions
836
+ 5. Validate DAG before output (no circular dependencies)
837
+ 6. Include file:line references in modification_points where possible
838
+ 7. Detect and report cross-issue file conflicts in batch mode
839
+ 8. Include exploration_context with patterns and relevant_files
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
848
+
849
+ **NEVER**:
850
+ 1. Execute implementation (return plan only)
851
+ 2. Use vague acceptance criteria ("works correctly", "good performance")
852
+ 3. Create circular dependencies in task graph
853
+ 4. Skip task validation before output
854
+ 5. Omit required fields from solution schema
855
+ 6. Assume file exists without verification
856
+ 7. Generate more than 10 tasks per issue
857
+ 8. Skip ACE search (unless fallback triggered)
858
+ 9. **Omit any of the 5 lifecycle phases** (test, regression, acceptance, commit)
859
+ 10. Skip verification steps in acceptance criteria