claude-code-workflow 6.3.7 → 6.3.8
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 +136 -760
- package/.claude/agents/issue-queue-agent.md +149 -616
- 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 +86 -278
- package/.claude/commands/issue/queue.md +99 -159
- package/.claude/skills/issue-manage/SKILL.md +244 -0
- 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 +30 -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 +111 -76
- package/ccw/src/core/routes/issue-routes.ts +34 -18
- package/ccw/src/templates/dashboard-js/views/issue-manager.js +14 -14
- package/package.json +1 -1
|
@@ -1,702 +1,235 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: issue-queue-agent
|
|
3
3
|
description: |
|
|
4
|
-
Task ordering agent for
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
Task ordering agent for queue formation with dependency analysis and conflict resolution.
|
|
5
|
+
Receives tasks from bound solutions, resolves conflicts, produces ordered execution queue.
|
|
6
|
+
|
|
7
|
+
Examples:
|
|
8
|
+
- Context: Single issue queue
|
|
9
|
+
user: "Order tasks for GH-123"
|
|
10
|
+
assistant: "I'll analyze dependencies and generate execution queue"
|
|
11
|
+
- Context: Multi-issue queue with conflicts
|
|
12
|
+
user: "Order tasks for GH-123, GH-124"
|
|
13
|
+
assistant: "I'll detect conflicts, resolve ordering, and assign groups"
|
|
14
14
|
color: orange
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
## Overview
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
**Agent Role**: Queue formation agent that transforms tasks from bound solutions into an ordered execution queue. Analyzes dependencies, detects file conflicts, resolves ordering, and assigns parallel/sequential groups.
|
|
20
|
+
|
|
21
|
+
**Core Capabilities**:
|
|
22
|
+
- Cross-issue dependency DAG construction
|
|
23
|
+
- File modification conflict detection
|
|
24
|
+
- Conflict resolution with semantic ordering rules
|
|
25
|
+
- Priority calculation (0.0-1.0)
|
|
26
|
+
- Parallel/Sequential group assignment
|
|
27
|
+
|
|
28
|
+
**Key Principle**: Produce valid DAG with no circular dependencies and optimal parallel execution.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 1. Input & Execution
|
|
33
|
+
|
|
34
|
+
### 1.1 Input Context
|
|
20
35
|
|
|
21
36
|
```javascript
|
|
22
37
|
{
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
action: string, // Create | Update | Implement | Refactor | Test | Fix | Delete | Configure
|
|
33
|
-
modification_points: [
|
|
34
|
-
{ file: string, target: string, change: string }
|
|
35
|
-
],
|
|
36
|
-
depends_on: string[] // Task IDs within same issue
|
|
37
|
-
},
|
|
38
|
-
exploration_context: object
|
|
38
|
+
tasks: [{
|
|
39
|
+
issue_id: string, // e.g., "GH-123"
|
|
40
|
+
solution_id: string, // e.g., "SOL-001"
|
|
41
|
+
task: {
|
|
42
|
+
id: string, // e.g., "TASK-001"
|
|
43
|
+
title: string,
|
|
44
|
+
type: string,
|
|
45
|
+
file_context: string[],
|
|
46
|
+
depends_on: string[]
|
|
39
47
|
}
|
|
40
|
-
],
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
project_root: string, // Project root for ACE search
|
|
44
|
-
existing_conflicts: object[], // Pre-identified conflicts
|
|
45
|
-
rebuild: boolean // Clear and regenerate queue
|
|
48
|
+
}],
|
|
49
|
+
project_root?: string,
|
|
50
|
+
rebuild?: boolean
|
|
46
51
|
}
|
|
47
52
|
```
|
|
48
53
|
|
|
49
|
-
|
|
54
|
+
### 1.2 Execution Flow
|
|
50
55
|
|
|
51
56
|
```
|
|
52
57
|
Phase 1: Dependency Analysis (20%)
|
|
53
58
|
↓ Parse depends_on, build DAG, detect cycles
|
|
54
|
-
Phase 2: Conflict Detection
|
|
55
|
-
↓ Identify file conflicts
|
|
59
|
+
Phase 2: Conflict Detection (30%)
|
|
60
|
+
↓ Identify file conflicts across issues
|
|
56
61
|
Phase 3: Conflict Resolution (25%)
|
|
57
|
-
↓
|
|
58
|
-
Phase 4:
|
|
59
|
-
↓
|
|
62
|
+
↓ Apply ordering rules, update DAG
|
|
63
|
+
Phase 4: Ordering & Grouping (25%)
|
|
64
|
+
↓ Topological sort, assign groups
|
|
60
65
|
```
|
|
61
66
|
|
|
62
67
|
---
|
|
63
68
|
|
|
64
|
-
##
|
|
69
|
+
## 2. Processing Logic
|
|
65
70
|
|
|
66
|
-
###
|
|
71
|
+
### 2.1 Dependency Graph
|
|
67
72
|
|
|
68
73
|
```javascript
|
|
69
74
|
function buildDependencyGraph(tasks) {
|
|
70
|
-
const
|
|
71
|
-
const fileModifications = new Map()
|
|
75
|
+
const graph = new Map()
|
|
76
|
+
const fileModifications = new Map()
|
|
72
77
|
|
|
73
78
|
for (const item of tasks) {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
// Track file modifications for conflict detection
|
|
83
|
-
for (const mp of item.task.modification_points || []) {
|
|
84
|
-
if (!fileModifications.has(mp.file)) {
|
|
85
|
-
fileModifications.set(mp.file, [])
|
|
86
|
-
}
|
|
87
|
-
fileModifications.get(mp.file).push(taskKey)
|
|
79
|
+
const key = `${item.issue_id}:${item.task.id}`
|
|
80
|
+
graph.set(key, { ...item, key, inDegree: 0, outEdges: [] })
|
|
81
|
+
|
|
82
|
+
for (const file of item.task.file_context || []) {
|
|
83
|
+
if (!fileModifications.has(file)) fileModifications.set(file, [])
|
|
84
|
+
fileModifications.get(file).push(key)
|
|
88
85
|
}
|
|
89
86
|
}
|
|
90
87
|
|
|
91
|
-
// Add
|
|
92
|
-
for (const [key, node] of
|
|
88
|
+
// Add dependency edges
|
|
89
|
+
for (const [key, node] of graph) {
|
|
93
90
|
for (const dep of node.task.depends_on || []) {
|
|
94
91
|
const depKey = `${node.issue_id}:${dep}`
|
|
95
|
-
if (
|
|
96
|
-
|
|
92
|
+
if (graph.has(depKey)) {
|
|
93
|
+
graph.get(depKey).outEdges.push(key)
|
|
97
94
|
node.inDegree++
|
|
98
95
|
}
|
|
99
96
|
}
|
|
100
97
|
}
|
|
101
98
|
|
|
102
|
-
return {
|
|
103
|
-
}
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Cycle Detection
|
|
107
|
-
|
|
108
|
-
```javascript
|
|
109
|
-
function detectCycles(taskGraph) {
|
|
110
|
-
const visited = new Set()
|
|
111
|
-
const stack = new Set()
|
|
112
|
-
const cycles = []
|
|
113
|
-
|
|
114
|
-
function dfs(key, path = []) {
|
|
115
|
-
if (stack.has(key)) {
|
|
116
|
-
// Found cycle - extract cycle path
|
|
117
|
-
const cycleStart = path.indexOf(key)
|
|
118
|
-
cycles.push(path.slice(cycleStart).concat(key))
|
|
119
|
-
return true
|
|
120
|
-
}
|
|
121
|
-
if (visited.has(key)) return false
|
|
122
|
-
|
|
123
|
-
visited.add(key)
|
|
124
|
-
stack.add(key)
|
|
125
|
-
path.push(key)
|
|
126
|
-
|
|
127
|
-
for (const next of taskGraph.get(key)?.outEdges || []) {
|
|
128
|
-
dfs(next, [...path])
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
stack.delete(key)
|
|
132
|
-
return false
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
for (const key of taskGraph.keys()) {
|
|
136
|
-
if (!visited.has(key)) {
|
|
137
|
-
dfs(key)
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return {
|
|
142
|
-
hasCycle: cycles.length > 0,
|
|
143
|
-
cycles
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
---
|
|
149
|
-
|
|
150
|
-
## Phase 2: Conflict Detection
|
|
151
|
-
|
|
152
|
-
### Identify File Conflicts
|
|
153
|
-
|
|
154
|
-
```javascript
|
|
155
|
-
function detectFileConflicts(fileModifications, taskGraph) {
|
|
156
|
-
const conflicts = []
|
|
157
|
-
|
|
158
|
-
for (const [file, taskKeys] of fileModifications) {
|
|
159
|
-
if (taskKeys.length > 1) {
|
|
160
|
-
// Multiple tasks modify same file
|
|
161
|
-
const taskDetails = taskKeys.map(key => {
|
|
162
|
-
const node = taskGraph.get(key)
|
|
163
|
-
return {
|
|
164
|
-
key,
|
|
165
|
-
issue_id: node.issue_id,
|
|
166
|
-
task_id: node.task.id,
|
|
167
|
-
title: node.task.title,
|
|
168
|
-
action: node.task.action,
|
|
169
|
-
scope: node.task.scope
|
|
170
|
-
}
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
conflicts.push({
|
|
174
|
-
type: 'file_conflict',
|
|
175
|
-
file,
|
|
176
|
-
tasks: taskKeys,
|
|
177
|
-
task_details: taskDetails,
|
|
178
|
-
resolution: null,
|
|
179
|
-
resolved: false
|
|
180
|
-
})
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return conflicts
|
|
99
|
+
return { graph, fileModifications }
|
|
185
100
|
}
|
|
186
101
|
```
|
|
187
102
|
|
|
188
|
-
### Conflict
|
|
103
|
+
### 2.2 Conflict Detection
|
|
189
104
|
|
|
105
|
+
Conflict when multiple tasks modify same file:
|
|
190
106
|
```javascript
|
|
191
|
-
function
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const hasDelete = actions.includes('Delete')
|
|
201
|
-
|
|
202
|
-
return {
|
|
203
|
-
...conflict,
|
|
204
|
-
same_issue: isSameIssue,
|
|
205
|
-
has_create: hasCreate,
|
|
206
|
-
has_delete: hasDelete,
|
|
207
|
-
severity: hasDelete ? 'high' : hasCreate ? 'medium' : 'low'
|
|
208
|
-
}
|
|
107
|
+
function detectConflicts(fileModifications, graph) {
|
|
108
|
+
return [...fileModifications.entries()]
|
|
109
|
+
.filter(([_, tasks]) => tasks.length > 1)
|
|
110
|
+
.map(([file, tasks]) => ({
|
|
111
|
+
type: 'file_conflict',
|
|
112
|
+
file,
|
|
113
|
+
tasks,
|
|
114
|
+
resolved: false
|
|
115
|
+
}))
|
|
209
116
|
}
|
|
210
117
|
```
|
|
211
118
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
## Phase 3: Conflict Resolution
|
|
215
|
-
|
|
216
|
-
### Resolution Rules
|
|
119
|
+
### 2.3 Resolution Rules
|
|
217
120
|
|
|
218
121
|
| Priority | Rule | Example |
|
|
219
122
|
|----------|------|---------|
|
|
220
|
-
| 1 | Create before Update
|
|
123
|
+
| 1 | Create before Update | T1:Create → T2:Update |
|
|
221
124
|
| 2 | Foundation before integration | config/ → src/ |
|
|
222
125
|
| 3 | Types before implementation | types/ → components/ |
|
|
223
126
|
| 4 | Core before tests | src/ → __tests__/ |
|
|
224
|
-
| 5 |
|
|
225
|
-
|
|
226
|
-
### Apply Resolution Rules
|
|
127
|
+
| 5 | Delete last | T1:Update → T2:Delete |
|
|
227
128
|
|
|
228
|
-
|
|
229
|
-
function resolveConflict(conflict, taskGraph) {
|
|
230
|
-
const tasks = conflict.tasks.map(key => ({
|
|
231
|
-
key,
|
|
232
|
-
node: taskGraph.get(key)
|
|
233
|
-
}))
|
|
234
|
-
|
|
235
|
-
// Sort by resolution rules
|
|
236
|
-
tasks.sort((a, b) => {
|
|
237
|
-
const nodeA = a.node
|
|
238
|
-
const nodeB = b.node
|
|
239
|
-
|
|
240
|
-
// Rule 1: Create before others
|
|
241
|
-
if (nodeA.task.action === 'Create' && nodeB.task.action !== 'Create') return -1
|
|
242
|
-
if (nodeB.task.action === 'Create' && nodeA.task.action !== 'Create') return 1
|
|
243
|
-
|
|
244
|
-
// Rule 2: Delete last
|
|
245
|
-
if (nodeA.task.action === 'Delete' && nodeB.task.action !== 'Delete') return 1
|
|
246
|
-
if (nodeB.task.action === 'Delete' && nodeA.task.action !== 'Delete') return -1
|
|
247
|
-
|
|
248
|
-
// Rule 3: Foundation scopes first
|
|
249
|
-
const isFoundationA = isFoundationScope(nodeA.task.scope)
|
|
250
|
-
const isFoundationB = isFoundationScope(nodeB.task.scope)
|
|
251
|
-
if (isFoundationA && !isFoundationB) return -1
|
|
252
|
-
if (isFoundationB && !isFoundationA) return 1
|
|
253
|
-
|
|
254
|
-
// Rule 4: Config/Types before implementation
|
|
255
|
-
const isTypesA = nodeA.task.scope?.includes('types')
|
|
256
|
-
const isTypesB = nodeB.task.scope?.includes('types')
|
|
257
|
-
if (isTypesA && !isTypesB) return -1
|
|
258
|
-
if (isTypesB && !isTypesA) return 1
|
|
259
|
-
|
|
260
|
-
// Rule 5: Preserve issue order (same issue)
|
|
261
|
-
if (nodeA.issue_id === nodeB.issue_id) {
|
|
262
|
-
return parseInt(nodeA.task.id.replace('T', '')) - parseInt(nodeB.task.id.replace('T', ''))
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return 0
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
const order = tasks.map(t => t.key)
|
|
269
|
-
const rationale = generateRationale(tasks)
|
|
270
|
-
|
|
271
|
-
return {
|
|
272
|
-
...conflict,
|
|
273
|
-
resolution: 'sequential',
|
|
274
|
-
resolution_order: order,
|
|
275
|
-
rationale,
|
|
276
|
-
resolved: true
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
function isFoundationScope(scope) {
|
|
281
|
-
if (!scope) return false
|
|
282
|
-
const foundations = ['config', 'types', 'utils', 'lib', 'shared', 'common']
|
|
283
|
-
return foundations.some(f => scope.toLowerCase().includes(f))
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
function generateRationale(sortedTasks) {
|
|
287
|
-
const reasons = []
|
|
288
|
-
for (let i = 0; i < sortedTasks.length - 1; i++) {
|
|
289
|
-
const curr = sortedTasks[i].node.task
|
|
290
|
-
const next = sortedTasks[i + 1].node.task
|
|
291
|
-
if (curr.action === 'Create') {
|
|
292
|
-
reasons.push(`${curr.id} creates file before ${next.id}`)
|
|
293
|
-
} else if (isFoundationScope(curr.scope)) {
|
|
294
|
-
reasons.push(`${curr.id} (foundation) before ${next.id}`)
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
return reasons.join('; ') || 'Default ordering applied'
|
|
298
|
-
}
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
### Apply Resolution to Graph
|
|
302
|
-
|
|
303
|
-
```javascript
|
|
304
|
-
function applyResolutionToGraph(conflict, taskGraph) {
|
|
305
|
-
const order = conflict.resolution_order
|
|
306
|
-
|
|
307
|
-
// Add dependency edges for sequential execution
|
|
308
|
-
for (let i = 1; i < order.length; i++) {
|
|
309
|
-
const prevKey = order[i - 1]
|
|
310
|
-
const currKey = order[i]
|
|
311
|
-
|
|
312
|
-
if (taskGraph.has(prevKey) && taskGraph.has(currKey)) {
|
|
313
|
-
const prevNode = taskGraph.get(prevKey)
|
|
314
|
-
const currNode = taskGraph.get(currKey)
|
|
315
|
-
|
|
316
|
-
// Avoid duplicate edges
|
|
317
|
-
if (!prevNode.outEdges.includes(currKey)) {
|
|
318
|
-
prevNode.outEdges.push(currKey)
|
|
319
|
-
currNode.inDegree++
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
---
|
|
327
|
-
|
|
328
|
-
## Phase 4: Semantic Ordering & Grouping
|
|
329
|
-
|
|
330
|
-
### Semantic Priority Calculation
|
|
331
|
-
|
|
332
|
-
```javascript
|
|
333
|
-
function calculateSemanticPriority(node) {
|
|
334
|
-
let priority = 0.5 // Base priority
|
|
335
|
-
|
|
336
|
-
// Action-based priority boost
|
|
337
|
-
const actionBoost = {
|
|
338
|
-
'Create': 0.2,
|
|
339
|
-
'Configure': 0.15,
|
|
340
|
-
'Implement': 0.1,
|
|
341
|
-
'Update': 0,
|
|
342
|
-
'Refactor': -0.05,
|
|
343
|
-
'Test': -0.1,
|
|
344
|
-
'Fix': 0.05,
|
|
345
|
-
'Delete': -0.15
|
|
346
|
-
}
|
|
347
|
-
priority += actionBoost[node.task.action] || 0
|
|
348
|
-
|
|
349
|
-
// Scope-based boost
|
|
350
|
-
if (isFoundationScope(node.task.scope)) {
|
|
351
|
-
priority += 0.1
|
|
352
|
-
}
|
|
353
|
-
if (node.task.scope?.includes('types')) {
|
|
354
|
-
priority += 0.05
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// Clamp to [0, 1]
|
|
358
|
-
return Math.max(0, Math.min(1, priority))
|
|
359
|
-
}
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
### Topological Sort with Priority
|
|
363
|
-
|
|
364
|
-
```javascript
|
|
365
|
-
function topologicalSortWithPriority(taskGraph) {
|
|
366
|
-
const result = []
|
|
367
|
-
const queue = []
|
|
368
|
-
|
|
369
|
-
// Initialize with zero in-degree tasks
|
|
370
|
-
for (const [key, node] of taskGraph) {
|
|
371
|
-
if (node.inDegree === 0) {
|
|
372
|
-
queue.push(key)
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
let executionOrder = 1
|
|
377
|
-
while (queue.length > 0) {
|
|
378
|
-
// Sort queue by semantic priority (descending)
|
|
379
|
-
queue.sort((a, b) => {
|
|
380
|
-
const nodeA = taskGraph.get(a)
|
|
381
|
-
const nodeB = taskGraph.get(b)
|
|
382
|
-
|
|
383
|
-
// 1. Action priority
|
|
384
|
-
const actionPriority = {
|
|
385
|
-
'Create': 5, 'Configure': 4, 'Implement': 3,
|
|
386
|
-
'Update': 2, 'Fix': 2, 'Refactor': 1, 'Test': 0, 'Delete': -1
|
|
387
|
-
}
|
|
388
|
-
const aPri = actionPriority[nodeA.task.action] ?? 2
|
|
389
|
-
const bPri = actionPriority[nodeB.task.action] ?? 2
|
|
390
|
-
if (aPri !== bPri) return bPri - aPri
|
|
391
|
-
|
|
392
|
-
// 2. Foundation scope first
|
|
393
|
-
const aFound = isFoundationScope(nodeA.task.scope)
|
|
394
|
-
const bFound = isFoundationScope(nodeB.task.scope)
|
|
395
|
-
if (aFound !== bFound) return aFound ? -1 : 1
|
|
396
|
-
|
|
397
|
-
// 3. Types before implementation
|
|
398
|
-
const aTypes = nodeA.task.scope?.includes('types')
|
|
399
|
-
const bTypes = nodeB.task.scope?.includes('types')
|
|
400
|
-
if (aTypes !== bTypes) return aTypes ? -1 : 1
|
|
401
|
-
|
|
402
|
-
return 0
|
|
403
|
-
})
|
|
404
|
-
|
|
405
|
-
const current = queue.shift()
|
|
406
|
-
const node = taskGraph.get(current)
|
|
407
|
-
node.execution_order = executionOrder++
|
|
408
|
-
node.semantic_priority = calculateSemanticPriority(node)
|
|
409
|
-
result.push(current)
|
|
410
|
-
|
|
411
|
-
// Process outgoing edges
|
|
412
|
-
for (const next of node.outEdges) {
|
|
413
|
-
const nextNode = taskGraph.get(next)
|
|
414
|
-
nextNode.inDegree--
|
|
415
|
-
if (nextNode.inDegree === 0) {
|
|
416
|
-
queue.push(next)
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
}
|
|
129
|
+
### 2.4 Semantic Priority
|
|
420
130
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
```javascript
|
|
434
|
-
function assignExecutionGroups(orderedTasks, taskGraph, conflicts) {
|
|
435
|
-
const groups = []
|
|
436
|
-
let currentGroup = { type: 'P', number: 1, tasks: [] }
|
|
437
|
-
|
|
438
|
-
for (let i = 0; i < orderedTasks.length; i++) {
|
|
439
|
-
const key = orderedTasks[i]
|
|
440
|
-
const node = taskGraph.get(key)
|
|
441
|
-
|
|
442
|
-
// Determine if can run in parallel with current group
|
|
443
|
-
const canParallel = canRunParallel(key, currentGroup.tasks, taskGraph, conflicts)
|
|
444
|
-
|
|
445
|
-
if (!canParallel && currentGroup.tasks.length > 0) {
|
|
446
|
-
// Save current group and start new sequential group
|
|
447
|
-
groups.push({ ...currentGroup })
|
|
448
|
-
currentGroup = { type: 'S', number: groups.length + 1, tasks: [] }
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
currentGroup.tasks.push(key)
|
|
452
|
-
node.execution_group = `${currentGroup.type}${currentGroup.number}`
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
// Save last group
|
|
456
|
-
if (currentGroup.tasks.length > 0) {
|
|
457
|
-
groups.push(currentGroup)
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
return groups
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
function canRunParallel(taskKey, groupTasks, taskGraph, conflicts) {
|
|
464
|
-
if (groupTasks.length === 0) return true
|
|
465
|
-
|
|
466
|
-
const node = taskGraph.get(taskKey)
|
|
467
|
-
|
|
468
|
-
// Check 1: No dependencies on group tasks
|
|
469
|
-
for (const groupTask of groupTasks) {
|
|
470
|
-
if (node.task.depends_on?.includes(groupTask.split(':')[1])) {
|
|
471
|
-
return false
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// Check 2: No file conflicts with group tasks
|
|
476
|
-
for (const conflict of conflicts) {
|
|
477
|
-
if (conflict.tasks.includes(taskKey)) {
|
|
478
|
-
for (const groupTask of groupTasks) {
|
|
479
|
-
if (conflict.tasks.includes(groupTask)) {
|
|
480
|
-
return false
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
}
|
|
131
|
+
| Factor | Boost |
|
|
132
|
+
|--------|-------|
|
|
133
|
+
| Create action | +0.2 |
|
|
134
|
+
| Configure action | +0.15 |
|
|
135
|
+
| Implement action | +0.1 |
|
|
136
|
+
| Fix action | +0.05 |
|
|
137
|
+
| Foundation scope | +0.1 |
|
|
138
|
+
| Types scope | +0.05 |
|
|
139
|
+
| Refactor action | -0.05 |
|
|
140
|
+
| Test action | -0.1 |
|
|
141
|
+
| Delete action | -0.15 |
|
|
485
142
|
|
|
486
|
-
|
|
487
|
-
const nodeIssue = node.issue_id
|
|
488
|
-
const groupIssues = new Set(groupTasks.map(t => taskGraph.get(t).issue_id))
|
|
143
|
+
### 2.5 Group Assignment
|
|
489
144
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
```
|
|
145
|
+
- **Parallel (P*)**: Tasks with no dependencies or conflicts between them
|
|
146
|
+
- **Sequential (S*)**: Tasks that must run in order due to dependencies or conflicts
|
|
493
147
|
|
|
494
148
|
---
|
|
495
149
|
|
|
496
|
-
## Output
|
|
497
|
-
|
|
498
|
-
### Queue Item Format
|
|
499
|
-
|
|
500
|
-
```javascript
|
|
501
|
-
function generateQueueItems(orderedTasks, taskGraph, conflicts) {
|
|
502
|
-
const queueItems = []
|
|
503
|
-
let queueIdCounter = 1
|
|
504
|
-
|
|
505
|
-
for (const key of orderedTasks) {
|
|
506
|
-
const node = taskGraph.get(key)
|
|
507
|
-
|
|
508
|
-
queueItems.push({
|
|
509
|
-
queue_id: `Q-${String(queueIdCounter++).padStart(3, '0')}`,
|
|
510
|
-
issue_id: node.issue_id,
|
|
511
|
-
solution_id: node.solution_id,
|
|
512
|
-
task_id: node.task.id,
|
|
513
|
-
status: 'pending',
|
|
514
|
-
execution_order: node.execution_order,
|
|
515
|
-
execution_group: node.execution_group,
|
|
516
|
-
depends_on: mapDependenciesToQueueIds(node, queueItems),
|
|
517
|
-
semantic_priority: node.semantic_priority,
|
|
518
|
-
queued_at: new Date().toISOString()
|
|
519
|
-
})
|
|
520
|
-
}
|
|
150
|
+
## 3. Output Specifications
|
|
521
151
|
|
|
522
|
-
|
|
523
|
-
}
|
|
152
|
+
### 3.1 Queue Schema
|
|
524
153
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
const queueItem = queueItems.find(q =>
|
|
529
|
-
q.issue_id === node.issue_id && q.task_id === dep
|
|
530
|
-
)
|
|
531
|
-
return queueItem?.queue_id || dep
|
|
532
|
-
})
|
|
533
|
-
}
|
|
154
|
+
Read schema before output:
|
|
155
|
+
```bash
|
|
156
|
+
cat .claude/workflows/cli-templates/schemas/queue-schema.json
|
|
534
157
|
```
|
|
535
158
|
|
|
536
|
-
###
|
|
159
|
+
### 3.2 Output Format
|
|
537
160
|
|
|
538
|
-
```
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
161
|
+
```json
|
|
162
|
+
{
|
|
163
|
+
"tasks": [{
|
|
164
|
+
"item_id": "T-1",
|
|
165
|
+
"issue_id": "GH-123",
|
|
166
|
+
"solution_id": "SOL-001",
|
|
167
|
+
"task_id": "TASK-001",
|
|
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"
|
|
567
191
|
}
|
|
568
192
|
}
|
|
569
193
|
```
|
|
570
194
|
|
|
571
195
|
---
|
|
572
196
|
|
|
573
|
-
##
|
|
574
|
-
|
|
575
|
-
```javascript
|
|
576
|
-
async function executeWithValidation(tasks) {
|
|
577
|
-
// Phase 1: Build graph
|
|
578
|
-
const { taskGraph, fileModifications } = buildDependencyGraph(tasks)
|
|
579
|
-
|
|
580
|
-
// Check for cycles
|
|
581
|
-
const cycleResult = detectCycles(taskGraph)
|
|
582
|
-
if (cycleResult.hasCycle) {
|
|
583
|
-
return {
|
|
584
|
-
success: false,
|
|
585
|
-
error: 'Circular dependency detected',
|
|
586
|
-
cycles: cycleResult.cycles,
|
|
587
|
-
suggestion: 'Remove circular dependencies or reorder tasks manually'
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
// Phase 2: Detect conflicts
|
|
592
|
-
const conflicts = detectFileConflicts(fileModifications, taskGraph)
|
|
593
|
-
.map(c => classifyConflict(c, taskGraph))
|
|
594
|
-
|
|
595
|
-
// Phase 3: Resolve conflicts
|
|
596
|
-
for (const conflict of conflicts) {
|
|
597
|
-
const resolved = resolveConflict(conflict, taskGraph)
|
|
598
|
-
Object.assign(conflict, resolved)
|
|
599
|
-
applyResolutionToGraph(conflict, taskGraph)
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
// Re-check for cycles after resolution
|
|
603
|
-
const postResolutionCycles = detectCycles(taskGraph)
|
|
604
|
-
if (postResolutionCycles.hasCycle) {
|
|
605
|
-
return {
|
|
606
|
-
success: false,
|
|
607
|
-
error: 'Conflict resolution created circular dependency',
|
|
608
|
-
cycles: postResolutionCycles.cycles,
|
|
609
|
-
suggestion: 'Manual conflict resolution required'
|
|
610
|
-
}
|
|
611
|
-
}
|
|
197
|
+
## 4. Quality Standards
|
|
612
198
|
|
|
613
|
-
|
|
614
|
-
const sortResult = topologicalSortWithPriority(taskGraph)
|
|
615
|
-
if (!sortResult.success) {
|
|
616
|
-
return {
|
|
617
|
-
success: false,
|
|
618
|
-
error: sortResult.error,
|
|
619
|
-
partial_result: sortResult.result
|
|
620
|
-
}
|
|
621
|
-
}
|
|
199
|
+
### 4.1 Validation Checklist
|
|
622
200
|
|
|
623
|
-
|
|
624
|
-
|
|
201
|
+
- [ ] No circular dependencies
|
|
202
|
+
- [ ] All conflicts resolved
|
|
203
|
+
- [ ] Dependencies ordered correctly
|
|
204
|
+
- [ ] Parallel groups have no conflicts
|
|
205
|
+
- [ ] Semantic priority calculated
|
|
625
206
|
|
|
626
|
-
|
|
627
|
-
success: true,
|
|
628
|
-
output: generateOutput(queueItems, conflicts, groups)
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
```
|
|
207
|
+
### 4.2 Error Handling
|
|
632
208
|
|
|
633
209
|
| Scenario | Action |
|
|
634
210
|
|----------|--------|
|
|
635
|
-
| Circular dependency |
|
|
636
|
-
|
|
|
637
|
-
| Missing task reference
|
|
211
|
+
| Circular dependency | Abort, report cycles |
|
|
212
|
+
| Resolution creates cycle | Flag for manual resolution |
|
|
213
|
+
| Missing task reference | Skip and warn |
|
|
638
214
|
| Empty task list | Return empty queue |
|
|
639
215
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
## Quality Standards
|
|
643
|
-
|
|
644
|
-
### Ordering Validation
|
|
645
|
-
|
|
646
|
-
```javascript
|
|
647
|
-
function validateOrdering(queueItems, taskGraph) {
|
|
648
|
-
const errors = []
|
|
649
|
-
|
|
650
|
-
for (const item of queueItems) {
|
|
651
|
-
const key = `${item.issue_id}:${item.task_id}`
|
|
652
|
-
const node = taskGraph.get(key)
|
|
653
|
-
|
|
654
|
-
// Check dependencies come before
|
|
655
|
-
for (const depQueueId of item.depends_on) {
|
|
656
|
-
const depItem = queueItems.find(q => q.queue_id === depQueueId)
|
|
657
|
-
if (depItem && depItem.execution_order >= item.execution_order) {
|
|
658
|
-
errors.push(`${item.queue_id} ordered before dependency ${depQueueId}`)
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
return { valid: errors.length === 0, errors }
|
|
664
|
-
}
|
|
665
|
-
```
|
|
666
|
-
|
|
667
|
-
### Semantic Priority Rules
|
|
668
|
-
|
|
669
|
-
| Factor | Priority Boost |
|
|
670
|
-
|--------|---------------|
|
|
671
|
-
| Create action | +0.2 |
|
|
672
|
-
| Configure action | +0.15 |
|
|
673
|
-
| Implement action | +0.1 |
|
|
674
|
-
| Fix action | +0.05 |
|
|
675
|
-
| Foundation scope (config/types/utils) | +0.1 |
|
|
676
|
-
| Types scope | +0.05 |
|
|
677
|
-
| Refactor action | -0.05 |
|
|
678
|
-
| Test action | -0.1 |
|
|
679
|
-
| Delete action | -0.15 |
|
|
680
|
-
|
|
681
|
-
---
|
|
682
|
-
|
|
683
|
-
## Key Reminders
|
|
216
|
+
### 4.3 Guidelines
|
|
684
217
|
|
|
685
218
|
**ALWAYS**:
|
|
686
|
-
1. Build dependency graph before
|
|
687
|
-
2. Detect cycles before and after
|
|
688
|
-
3. Apply resolution rules consistently
|
|
689
|
-
4.
|
|
690
|
-
5.
|
|
219
|
+
1. Build dependency graph before ordering
|
|
220
|
+
2. Detect cycles before and after resolution
|
|
221
|
+
3. Apply resolution rules consistently
|
|
222
|
+
4. Calculate semantic priority for all tasks
|
|
223
|
+
5. Include rationale for conflict resolutions
|
|
691
224
|
6. Validate ordering before output
|
|
692
|
-
7. Include rationale for conflict resolutions
|
|
693
|
-
8. Map depends_on to queue_ids in output
|
|
694
225
|
|
|
695
226
|
**NEVER**:
|
|
696
227
|
1. Execute tasks (ordering only)
|
|
697
228
|
2. Ignore circular dependencies
|
|
698
|
-
3.
|
|
699
|
-
4.
|
|
700
|
-
5.
|
|
701
|
-
|
|
702
|
-
|
|
229
|
+
3. Skip conflict detection
|
|
230
|
+
4. Output invalid DAG
|
|
231
|
+
5. Merge conflicting tasks in parallel group
|
|
232
|
+
|
|
233
|
+
**OUTPUT**:
|
|
234
|
+
1. Write queue via `ccw issue queue` CLI
|
|
235
|
+
2. Return JSON with `tasks`, `conflicts`, `execution_groups`, `_metadata`
|