claude-code-workflow 6.3.11 → 6.3.13
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/CLAUDE.md +33 -33
- package/.claude/agents/issue-plan-agent.md +77 -5
- package/.claude/agents/issue-queue-agent.md +122 -18
- package/.claude/commands/issue/execute.md +53 -40
- package/.claude/commands/issue/new.md +113 -11
- package/.claude/commands/issue/plan.md +112 -37
- package/.claude/commands/issue/queue.md +28 -18
- package/.claude/skills/software-manual/scripts/assemble_docsify.py +584 -0
- package/.claude/skills/software-manual/templates/css/docsify-base.css +984 -0
- package/.claude/skills/software-manual/templates/docsify-shell.html +466 -0
- package/.claude/workflows/cli-templates/schemas/issues-jsonl-schema.json +141 -168
- package/.claude/workflows/cli-templates/schemas/solution-schema.json +3 -2
- package/.codex/prompts/issue-execute.md +3 -3
- package/.codex/prompts/issue-queue.md +3 -3
- package/ccw/dist/commands/issue.d.ts.map +1 -1
- package/ccw/dist/commands/issue.js +2 -1
- package/ccw/dist/commands/issue.js.map +1 -1
- package/ccw/src/commands/issue.ts +2 -1
- package/ccw/src/templates/dashboard-css/33-cli-stream-viewer.css +580 -467
- package/ccw/src/templates/dashboard-js/components/cli-stream-viewer.js +532 -461
- package/ccw/src/templates/dashboard-js/components/notifications.js +774 -774
- package/ccw/src/templates/dashboard-js/i18n.js +4 -0
- package/ccw/src/templates/dashboard.html +10 -0
- package/ccw/src/tools/claude-cli-tools.ts +388 -388
- package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/config.py +19 -3
- package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/ranking.py +15 -4
- package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/vector_store.py +57 -47
- package/codex-lens/src/codexlens/storage/__pycache__/registry.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/registry.py +114 -101
- package/package.json +83 -83
|
@@ -128,40 +128,46 @@ if (flags.allPending) {
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
//
|
|
132
|
-
function
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
131
|
+
// Semantic grouping via Gemini CLI (max 6 issues per group)
|
|
132
|
+
async function groupBySimilarityGemini(issues) {
|
|
133
|
+
const issueSummaries = issues.map(i => ({
|
|
134
|
+
id: i.id, title: i.title, tags: i.tags
|
|
135
|
+
}));
|
|
136
|
+
|
|
137
|
+
const prompt = `
|
|
138
|
+
PURPOSE: Group similar issues by semantic similarity for batch processing; maximize within-group coherence; max 6 issues per group
|
|
139
|
+
TASK: • Analyze issue titles/tags semantically • Identify functional/architectural clusters • Assign each issue to one group
|
|
140
|
+
MODE: analysis
|
|
141
|
+
CONTEXT: Issue metadata only
|
|
142
|
+
EXPECTED: JSON with groups array, each containing max 6 issue_ids, theme, rationale
|
|
143
|
+
RULES: $(cat ~/.claude/workflows/cli-templates/protocols/analysis-protocol.md) | Each issue in exactly one group | Max 6 issues per group | Balance group sizes
|
|
144
|
+
|
|
145
|
+
INPUT:
|
|
146
|
+
${JSON.stringify(issueSummaries, null, 2)}
|
|
147
|
+
|
|
148
|
+
OUTPUT FORMAT:
|
|
149
|
+
{"groups":[{"group_id":1,"theme":"...","issue_ids":["..."],"rationale":"..."}],"ungrouped":[]}
|
|
150
|
+
`;
|
|
151
|
+
|
|
152
|
+
const taskId = Bash({
|
|
153
|
+
command: `ccw cli -p "${prompt}" --tool gemini --mode analysis`,
|
|
154
|
+
run_in_background: true, timeout: 600000
|
|
155
|
+
});
|
|
156
|
+
const output = TaskOutput({ task_id: taskId, block: true });
|
|
157
|
+
|
|
158
|
+
// Extract JSON from potential markdown code blocks
|
|
159
|
+
function extractJsonFromMarkdown(text) {
|
|
160
|
+
const jsonMatch = text.match(/```json\s*\n([\s\S]*?)\n```/) ||
|
|
161
|
+
text.match(/```\s*\n([\s\S]*?)\n```/);
|
|
162
|
+
return jsonMatch ? jsonMatch[1] : text;
|
|
159
163
|
}
|
|
160
|
-
|
|
164
|
+
|
|
165
|
+
const result = JSON.parse(extractJsonFromMarkdown(output));
|
|
166
|
+
return result.groups.map(g => g.issue_ids.map(id => issues.find(i => i.id === id)));
|
|
161
167
|
}
|
|
162
168
|
|
|
163
|
-
const batches =
|
|
164
|
-
console.log(`Processing ${issues.length} issues in ${batches.length} batch(es) (
|
|
169
|
+
const batches = await groupBySimilarityGemini(issues);
|
|
170
|
+
console.log(`Processing ${issues.length} issues in ${batches.length} batch(es) (Gemini semantic grouping, max 6 issues/agent)`);
|
|
165
171
|
|
|
166
172
|
TodoWrite({
|
|
167
173
|
todos: batches.map((_, i) => ({
|
|
@@ -177,6 +183,7 @@ TodoWrite({
|
|
|
177
183
|
```javascript
|
|
178
184
|
Bash(`mkdir -p .workflow/issues/solutions`);
|
|
179
185
|
const pendingSelections = []; // Collect multi-solution issues for user selection
|
|
186
|
+
const agentResults = []; // Collect all agent results for conflict aggregation
|
|
180
187
|
|
|
181
188
|
// Build prompts for all batches
|
|
182
189
|
const agentTasks = batches.map((batch, batchIndex) => {
|
|
@@ -200,13 +207,15 @@ ${issueList}
|
|
|
200
207
|
### Steps
|
|
201
208
|
1. Fetch: \`ccw issue status <id> --json\`
|
|
202
209
|
2. Load project context (project-tech.json + project-guidelines.json)
|
|
203
|
-
3. **If
|
|
210
|
+
3. **If extended_context exists**: Use extended_context (location, suggested_fix, notes) as planning hints
|
|
204
211
|
4. Explore (ACE) → Plan solution (respecting guidelines)
|
|
205
212
|
5. Register & bind: \`ccw issue bind <id> --solution <file>\`
|
|
206
213
|
|
|
207
214
|
### Generate Files
|
|
208
215
|
\`.workflow/issues/solutions/{issue-id}.jsonl\` - Solution with tasks (schema: cat .claude/workflows/cli-templates/schemas/solution-schema.json)
|
|
209
216
|
|
|
217
|
+
**Solution ID Format**: \`SOL-{issue-id}-{seq}\` (e.g., \`SOL-GH-123-1\`, \`SOL-ISS-20251229-1\`)
|
|
218
|
+
|
|
210
219
|
### Binding Rules
|
|
211
220
|
- **Single solution**: Auto-bind via \`ccw issue bind <id> --solution <file>\`
|
|
212
221
|
- **Multiple solutions**: Register only, return for user selection
|
|
@@ -216,7 +225,13 @@ ${issueList}
|
|
|
216
225
|
{
|
|
217
226
|
"bound": [{ "issue_id": "...", "solution_id": "...", "task_count": N }],
|
|
218
227
|
"pending_selection": [{ "issue_id": "...", "solutions": [{ "id": "...", "description": "...", "task_count": N }] }],
|
|
219
|
-
"conflicts": [{
|
|
228
|
+
"conflicts": [{
|
|
229
|
+
"type": "file_conflict|api_conflict|data_conflict|dependency_conflict|architecture_conflict",
|
|
230
|
+
"severity": "high|medium|low",
|
|
231
|
+
"summary": "brief description",
|
|
232
|
+
"recommended_resolution": "auto-resolution for low/medium",
|
|
233
|
+
"resolution_options": [{ "strategy": "...", "rationale": "..." }]
|
|
234
|
+
}]
|
|
220
235
|
}
|
|
221
236
|
\`\`\`
|
|
222
237
|
`;
|
|
@@ -247,7 +262,18 @@ for (let i = 0; i < agentTasks.length; i += MAX_PARALLEL) {
|
|
|
247
262
|
// Collect results from this chunk
|
|
248
263
|
for (const { taskId, batchIndex } of taskIds) {
|
|
249
264
|
const result = TaskOutput(task_id=taskId, block=true);
|
|
250
|
-
|
|
265
|
+
|
|
266
|
+
// Extract JSON from potential markdown code blocks (agent may wrap in ```json...```)
|
|
267
|
+
const jsonText = extractJsonFromMarkdown(result);
|
|
268
|
+
let summary;
|
|
269
|
+
try {
|
|
270
|
+
summary = JSON.parse(jsonText);
|
|
271
|
+
} catch (e) {
|
|
272
|
+
console.log(`⚠ Batch ${batchIndex + 1}: Failed to parse agent result, skipping`);
|
|
273
|
+
updateTodo(`Plan batch ${batchIndex + 1}`, 'completed');
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
agentResults.push(summary); // Store for Phase 3 conflict aggregation
|
|
251
277
|
|
|
252
278
|
for (const item of summary.bound || []) {
|
|
253
279
|
console.log(`✓ ${item.issue_id}: ${item.solution_id} (${item.task_count} tasks)`);
|
|
@@ -258,17 +284,66 @@ for (let i = 0; i < agentTasks.length; i += MAX_PARALLEL) {
|
|
|
258
284
|
pendingSelections.push(pending);
|
|
259
285
|
}
|
|
260
286
|
if (summary.conflicts?.length > 0) {
|
|
261
|
-
console.log(`⚠ Conflicts: ${summary.conflicts.
|
|
287
|
+
console.log(`⚠ Conflicts: ${summary.conflicts.length} detected (will resolve in Phase 3)`);
|
|
262
288
|
}
|
|
263
289
|
updateTodo(`Plan batch ${batchIndex + 1}`, 'completed');
|
|
264
290
|
}
|
|
265
291
|
}
|
|
266
292
|
```
|
|
267
293
|
|
|
268
|
-
### Phase 3:
|
|
294
|
+
### Phase 3: Conflict Resolution & Solution Selection
|
|
269
295
|
|
|
270
296
|
```javascript
|
|
271
|
-
//
|
|
297
|
+
// Helper: Extract selected solution ID from AskUserQuestion answer
|
|
298
|
+
function extractSelectedSolutionId(answer, issueId) {
|
|
299
|
+
// answer format: { [header]: selectedLabel } or { answers: { [question]: label } }
|
|
300
|
+
const key = Object.keys(answer).find(k => k.includes(issueId));
|
|
301
|
+
if (!key) return null;
|
|
302
|
+
const selected = answer[key];
|
|
303
|
+
// Label format: "SOL-xxx (N tasks)" - extract solution ID
|
|
304
|
+
const match = selected.match(/^(SOL-[^\s]+)/);
|
|
305
|
+
return match ? match[1] : null;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Phase 3a: Aggregate and resolve conflicts from all agents
|
|
309
|
+
const allConflicts = [];
|
|
310
|
+
for (const result of agentResults) {
|
|
311
|
+
if (result.conflicts?.length > 0) {
|
|
312
|
+
allConflicts.push(...result.conflicts);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (allConflicts.length > 0) {
|
|
317
|
+
console.log(`\n## Resolving ${allConflicts.length} conflict(s) detected by agents\n`);
|
|
318
|
+
|
|
319
|
+
// ALWAYS confirm high-severity conflicts (per user preference)
|
|
320
|
+
const highSeverity = allConflicts.filter(c => c.severity === 'high');
|
|
321
|
+
const lowMedium = allConflicts.filter(c => c.severity !== 'high');
|
|
322
|
+
|
|
323
|
+
// Auto-resolve low/medium severity
|
|
324
|
+
for (const conflict of lowMedium) {
|
|
325
|
+
console.log(` Auto-resolved: ${conflict.summary} → ${conflict.recommended_resolution}`);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// ALWAYS require user confirmation for high severity
|
|
329
|
+
if (highSeverity.length > 0) {
|
|
330
|
+
const conflictAnswer = AskUserQuestion({
|
|
331
|
+
questions: highSeverity.slice(0, 4).map(conflict => ({
|
|
332
|
+
question: `${conflict.type}: ${conflict.summary}. How to resolve?`,
|
|
333
|
+
header: conflict.type.replace('_conflict', ''),
|
|
334
|
+
multiSelect: false,
|
|
335
|
+
options: conflict.resolution_options.map(opt => ({
|
|
336
|
+
label: opt.strategy,
|
|
337
|
+
description: opt.rationale
|
|
338
|
+
}))
|
|
339
|
+
}))
|
|
340
|
+
});
|
|
341
|
+
// Apply user-selected resolutions
|
|
342
|
+
console.log('Applied user-selected conflict resolutions');
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Phase 3b: Multi-Solution Selection (MANDATORY when pendingSelections > 0)
|
|
272
347
|
if (pendingSelections.length > 0) {
|
|
273
348
|
console.log(`\n## User Selection Required: ${pendingSelections.length} issue(s) have multiple solutions\n`);
|
|
274
349
|
|
|
@@ -89,7 +89,7 @@ Queue formation command using **issue-queue-agent** that analyzes all bound solu
|
|
|
89
89
|
{
|
|
90
90
|
"item_id": "S-1",
|
|
91
91
|
"issue_id": "ISS-20251227-003",
|
|
92
|
-
"solution_id": "SOL-20251227-003",
|
|
92
|
+
"solution_id": "SOL-ISS-20251227-003-1",
|
|
93
93
|
"status": "pending",
|
|
94
94
|
"execution_order": 1,
|
|
95
95
|
"execution_group": "P1",
|
|
@@ -102,7 +102,7 @@ Queue formation command using **issue-queue-agent** that analyzes all bound solu
|
|
|
102
102
|
{
|
|
103
103
|
"item_id": "S-2",
|
|
104
104
|
"issue_id": "ISS-20251227-001",
|
|
105
|
-
"solution_id": "SOL-20251227-001",
|
|
105
|
+
"solution_id": "SOL-ISS-20251227-001-1",
|
|
106
106
|
"status": "pending",
|
|
107
107
|
"execution_order": 2,
|
|
108
108
|
"execution_group": "P1",
|
|
@@ -115,7 +115,7 @@ Queue formation command using **issue-queue-agent** that analyzes all bound solu
|
|
|
115
115
|
{
|
|
116
116
|
"item_id": "S-3",
|
|
117
117
|
"issue_id": "ISS-20251227-002",
|
|
118
|
-
"solution_id": "SOL-20251227-002",
|
|
118
|
+
"solution_id": "SOL-ISS-20251227-002-1",
|
|
119
119
|
"status": "pending",
|
|
120
120
|
"execution_order": 3,
|
|
121
121
|
"execution_group": "S2",
|
|
@@ -329,27 +329,33 @@ const result = Task(
|
|
|
329
329
|
const summary = JSON.parse(result);
|
|
330
330
|
```
|
|
331
331
|
|
|
332
|
-
### Phase 5:
|
|
332
|
+
### Phase 5: Validation & Status Update
|
|
333
333
|
|
|
334
334
|
```javascript
|
|
335
|
-
|
|
335
|
+
const queuePath = `.workflow/issues/queues/${queueId}.json`;
|
|
336
|
+
|
|
337
|
+
// 1. Validate queue has solutions
|
|
338
|
+
const solCount = Bash(`jq ".solutions | length" "${queuePath}"`).trim();
|
|
339
|
+
if (!solCount || solCount === '0') {
|
|
340
|
+
console.error(`✗ Queue has no solutions. Aborting.`);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// 2. Update issue statuses
|
|
345
|
+
for (const id of summary.issues_queued) {
|
|
346
|
+
Bash(`ccw issue update ${id} --status queued`);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// 3. Summary
|
|
336
350
|
console.log(`
|
|
337
|
-
## Queue
|
|
351
|
+
## Queue: ${summary.queue_id}
|
|
338
352
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
**Groups**: ${summary.execution_groups.map(g => `${g.id}(${g.count})`).join(', ')}
|
|
343
|
-
**Conflicts Resolved**: ${summary.conflicts_resolved}
|
|
353
|
+
- Solutions: ${summary.total_solutions}
|
|
354
|
+
- Tasks: ${summary.total_tasks}
|
|
355
|
+
- Issues: ${summary.issues_queued.join(', ')}
|
|
344
356
|
|
|
345
|
-
Next:
|
|
357
|
+
Next: /issue:execute
|
|
346
358
|
`);
|
|
347
|
-
|
|
348
|
-
// Update issue statuses via CLI (use `update` for pure field changes)
|
|
349
|
-
// Note: `queue add` has its own logic; here we only need status update
|
|
350
|
-
for (const issueId of summary.issues_queued) {
|
|
351
|
-
Bash(`ccw issue update ${issueId} --status queued`);
|
|
352
|
-
}
|
|
353
359
|
```
|
|
354
360
|
|
|
355
361
|
## Error Handling
|
|
@@ -360,6 +366,10 @@ for (const issueId of summary.issues_queued) {
|
|
|
360
366
|
| Circular dependency | List cycles, abort queue formation |
|
|
361
367
|
| Unresolved conflicts | Agent resolves using ordering rules |
|
|
362
368
|
| Invalid task reference | Skip and warn |
|
|
369
|
+
| **index.json not updated** | Auto-fix: Set active_queue_id to new queue |
|
|
370
|
+
| **Wrong status value** | Auto-fix: Convert non-pending status to "pending" |
|
|
371
|
+
| **No entry points (all have deps)** | Auto-fix: Clear depends_on for first item |
|
|
372
|
+
| **Queue file missing solutions** | Abort with error, agent must regenerate |
|
|
363
373
|
|
|
364
374
|
## Related Commands
|
|
365
375
|
|