claude-code-workflow 6.3.40 → 6.3.42
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/commands/issue/plan.md +49 -56
- package/.claude/commands/issue/queue.md +16 -16
- package/.claude/commands/workflow/develop-with-file.md +1040 -0
- package/.codex/skills/ccw-loop/SKILL.md +2 -1
- package/.codex/skills/ccw-loop-b/SKILL.md +1 -0
- package/.codex/skills/parallel-dev-cycle/SKILL.md +1 -0
- package/ccw/dist/commands/issue.d.ts.map +1 -1
- package/ccw/dist/commands/issue.js +63 -0
- package/ccw/dist/commands/issue.js.map +1 -1
- package/ccw/src/commands/issue.ts +78 -0
- package/package.json +1 -1
|
@@ -59,7 +59,7 @@ Phase 1: Issue Loading
|
|
|
59
59
|
├─ Parse input (single, comma-separated, or --all-pending)
|
|
60
60
|
├─ Fetch issue metadata (ID, title, tags)
|
|
61
61
|
├─ Validate issues exist (create if needed)
|
|
62
|
-
└─
|
|
62
|
+
└─ Create batches by size (max 3 per batch by default)
|
|
63
63
|
|
|
64
64
|
Phase 2: Unified Explore + Plan (issue-plan-agent)
|
|
65
65
|
├─ Launch issue-plan-agent per batch
|
|
@@ -119,46 +119,17 @@ if (useAllPending) {
|
|
|
119
119
|
}
|
|
120
120
|
// Note: Agent fetches full issue content via `ccw issue status <id> --json`
|
|
121
121
|
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const prompt = `
|
|
129
|
-
PURPOSE: Group similar issues by semantic similarity for batch processing; maximize within-group coherence; max 4 issues per group
|
|
130
|
-
TASK: • Analyze issue titles/tags semantically • Identify functional/architectural clusters • Assign each issue to one group
|
|
131
|
-
MODE: analysis
|
|
132
|
-
CONTEXT: Issue metadata only
|
|
133
|
-
EXPECTED: JSON with groups array, each containing max 4 issue_ids, theme, rationale
|
|
134
|
-
CONSTRAINTS: Each issue in exactly one group | Max 4 issues per group | Balance group sizes
|
|
135
|
-
|
|
136
|
-
INPUT:
|
|
137
|
-
${JSON.stringify(issueSummaries, null, 2)}
|
|
138
|
-
|
|
139
|
-
OUTPUT FORMAT:
|
|
140
|
-
{"groups":[{"group_id":1,"theme":"...","issue_ids":["..."],"rationale":"..."}],"ungrouped":[]}
|
|
141
|
-
`;
|
|
142
|
-
|
|
143
|
-
const taskId = Bash({
|
|
144
|
-
command: `ccw cli -p "${prompt}" --tool gemini --mode analysis`,
|
|
145
|
-
run_in_background: true, timeout: 600000
|
|
146
|
-
});
|
|
147
|
-
const output = TaskOutput({ task_id: taskId, block: true });
|
|
148
|
-
|
|
149
|
-
// Extract JSON from potential markdown code blocks
|
|
150
|
-
function extractJsonFromMarkdown(text) {
|
|
151
|
-
const jsonMatch = text.match(/```json\s*\n([\s\S]*?)\n```/) ||
|
|
152
|
-
text.match(/```\s*\n([\s\S]*?)\n```/);
|
|
153
|
-
return jsonMatch ? jsonMatch[1] : text;
|
|
122
|
+
// Simple size-based batching (max batchSize issues per group)
|
|
123
|
+
function createBatches(issues, batchSize) {
|
|
124
|
+
const batches = [];
|
|
125
|
+
for (let i = 0; i < issues.length; i += batchSize) {
|
|
126
|
+
batches.push(issues.slice(i, i + batchSize));
|
|
154
127
|
}
|
|
155
|
-
|
|
156
|
-
const result = JSON.parse(extractJsonFromMarkdown(output));
|
|
157
|
-
return result.groups.map(g => g.issue_ids.map(id => issues.find(i => i.id === id)));
|
|
128
|
+
return batches;
|
|
158
129
|
}
|
|
159
130
|
|
|
160
|
-
const batches =
|
|
161
|
-
console.log(`Processing ${issues.length} issues in ${batches.length} batch(es) (max
|
|
131
|
+
const batches = createBatches(issues, batchSize);
|
|
132
|
+
console.log(`Processing ${issues.length} issues in ${batches.length} batch(es) (max ${batchSize} issues/agent)`);
|
|
162
133
|
|
|
163
134
|
TodoWrite({
|
|
164
135
|
todos: batches.map((_, i) => ({
|
|
@@ -207,7 +178,9 @@ ${issueList}
|
|
|
207
178
|
- Add explicit verification steps to prevent same failure mode
|
|
208
179
|
6. **If github_url exists**: Add final task to comment on GitHub issue
|
|
209
180
|
7. Write solution to: .workflow/issues/solutions/{issue-id}.jsonl
|
|
210
|
-
8.
|
|
181
|
+
8. **CRITICAL - Binding Decision**:
|
|
182
|
+
- Single solution → **MUST execute**: ccw issue bind <issue-id> <solution-id>
|
|
183
|
+
- Multiple solutions → Return pending_selection only (no bind)
|
|
211
184
|
|
|
212
185
|
### Failure-Aware Planning Rules
|
|
213
186
|
- **Extract failure patterns**: Parse issue.feedback where type='failure' and stage='execute'
|
|
@@ -265,35 +238,55 @@ for (let i = 0; i < agentTasks.length; i += MAX_PARALLEL) {
|
|
|
265
238
|
}
|
|
266
239
|
agentResults.push(summary); // Store for Phase 3 conflict aggregation
|
|
267
240
|
|
|
241
|
+
// Verify binding for bound issues (agent should have executed bind)
|
|
268
242
|
for (const item of summary.bound || []) {
|
|
269
|
-
|
|
243
|
+
const status = JSON.parse(Bash(`ccw issue status ${item.issue_id} --json`).trim());
|
|
244
|
+
if (status.bound_solution_id === item.solution_id) {
|
|
245
|
+
console.log(`✓ ${item.issue_id}: ${item.solution_id} (${item.task_count} tasks)`);
|
|
246
|
+
} else {
|
|
247
|
+
// Fallback: agent failed to bind, execute here
|
|
248
|
+
Bash(`ccw issue bind ${item.issue_id} ${item.solution_id}`);
|
|
249
|
+
console.log(`✓ ${item.issue_id}: ${item.solution_id} (${item.task_count} tasks) [recovered]`);
|
|
250
|
+
}
|
|
270
251
|
}
|
|
271
|
-
// Collect
|
|
252
|
+
// Collect pending selections for Phase 3
|
|
272
253
|
for (const pending of summary.pending_selection || []) {
|
|
273
|
-
console.log(`⏳ ${pending.issue_id}: ${pending.solutions.length} solutions → awaiting selection`);
|
|
274
254
|
pendingSelections.push(pending);
|
|
275
255
|
}
|
|
276
|
-
if (summary.conflicts?.length > 0) {
|
|
277
|
-
console.log(`⚠ Conflicts: ${summary.conflicts.length} detected (will resolve in Phase 3)`);
|
|
278
|
-
}
|
|
279
256
|
updateTodo(`Plan batch ${batchIndex + 1}`, 'completed');
|
|
280
257
|
}
|
|
281
258
|
}
|
|
282
259
|
```
|
|
283
260
|
|
|
284
|
-
### Phase 3:
|
|
261
|
+
### Phase 3: Solution Selection (if pending)
|
|
285
262
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
263
|
+
```javascript
|
|
264
|
+
// Handle multi-solution issues
|
|
265
|
+
for (const pending of pendingSelections) {
|
|
266
|
+
if (pending.solutions.length === 0) continue;
|
|
290
267
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
268
|
+
const options = pending.solutions.slice(0, 4).map(sol => ({
|
|
269
|
+
label: `${sol.id} (${sol.task_count} tasks)`,
|
|
270
|
+
description: sol.description || sol.approach || 'No description'
|
|
271
|
+
}));
|
|
272
|
+
|
|
273
|
+
const answer = AskUserQuestion({
|
|
274
|
+
questions: [{
|
|
275
|
+
question: `Issue ${pending.issue_id}: which solution to bind?`,
|
|
276
|
+
header: pending.issue_id,
|
|
277
|
+
options: options,
|
|
278
|
+
multiSelect: false
|
|
279
|
+
}]
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
const selected = answer[Object.keys(answer)[0]];
|
|
283
|
+
if (!selected || selected === 'Other') continue;
|
|
284
|
+
|
|
285
|
+
const solId = selected.split(' ')[0];
|
|
286
|
+
Bash(`ccw issue bind ${pending.issue_id} ${solId}`);
|
|
287
|
+
console.log(`✓ ${pending.issue_id}: ${solId} bound`);
|
|
288
|
+
}
|
|
289
|
+
```
|
|
297
290
|
|
|
298
291
|
### Phase 4: Summary
|
|
299
292
|
|
|
@@ -28,12 +28,13 @@ Queue formation command using **issue-queue-agent** that analyzes all bound solu
|
|
|
28
28
|
| Operation | Correct | Incorrect |
|
|
29
29
|
|-----------|---------|-----------|
|
|
30
30
|
| List issues (brief) | `ccw issue list --status planned --brief` | `Read('issues.jsonl')` |
|
|
31
|
+
| **Batch solutions (NEW)** | `ccw issue solutions --status planned --brief` | Loop `ccw issue solution <id>` |
|
|
31
32
|
| List queue (brief) | `ccw issue queue --brief` | `Read('queues/*.json')` |
|
|
32
33
|
| Read issue details | `ccw issue status <id> --json` | `Read('issues.jsonl')` |
|
|
33
34
|
| Get next item | `ccw issue next --json` | `Read('queues/*.json')` |
|
|
34
35
|
| Update status | `ccw issue update <id> --status ...` | Direct file edit |
|
|
35
36
|
| Sync from queue | `ccw issue update --from-queue` | Direct file edit |
|
|
36
|
-
|
|
|
37
|
+
| Read solution (single) | `ccw issue solution <id> --brief` | `Read('solutions/*.jsonl')` |
|
|
37
38
|
|
|
38
39
|
**Output Options**:
|
|
39
40
|
- `--brief`: JSON with minimal fields (id, status, counts)
|
|
@@ -131,24 +132,23 @@ Phase 7: Active Queue Check & Decision (REQUIRED)
|
|
|
131
132
|
### Phase 1: Solution Loading & Distribution
|
|
132
133
|
|
|
133
134
|
**Data Loading:**
|
|
134
|
-
- Use `ccw issue
|
|
135
|
-
-
|
|
136
|
-
|
|
137
|
-
**Solution Brief Loading** (for each planned issue):
|
|
138
|
-
```bash
|
|
139
|
-
ccw issue solution <issue-id> --brief
|
|
140
|
-
# Returns: [{ solution_id, is_bound, task_count, files_touched[] }]
|
|
141
|
-
```
|
|
135
|
+
- Use `ccw issue solutions --status planned --brief` to get all planned issues with solutions in **one call**
|
|
136
|
+
- Returns: Array of `{ issue_id, solution_id, is_bound, task_count, files_touched[], priority }`
|
|
137
|
+
- If no bound solutions found → display message, suggest `/issue:plan`
|
|
142
138
|
|
|
143
139
|
**Build Solution Objects:**
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
140
|
+
```javascript
|
|
141
|
+
// Single CLI call replaces N individual queries
|
|
142
|
+
const result = Bash(`ccw issue solutions --status planned --brief`).trim();
|
|
143
|
+
const solutions = result ? JSON.parse(result) : [];
|
|
144
|
+
|
|
145
|
+
if (solutions.length === 0) {
|
|
146
|
+
console.log('No bound solutions found. Run /issue:plan first.');
|
|
147
|
+
return;
|
|
151
148
|
}
|
|
149
|
+
|
|
150
|
+
// solutions already in correct format:
|
|
151
|
+
// { issue_id, solution_id, is_bound, task_count, files_touched[], priority }
|
|
152
152
|
```
|
|
153
153
|
|
|
154
154
|
**Multi-Queue Distribution** (if `--queues > 1`):
|