claude-code-workflow 6.3.6 → 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.
@@ -51,51 +51,18 @@ interface Issue {
51
51
  }
52
52
  ```
53
53
 
54
- ## Task Lifecycle (Each Task is Closed-Loop)
54
+ ## Lifecycle Requirements
55
55
 
56
- When `/issue:plan` generates tasks, each task MUST include:
56
+ The `lifecycle_requirements` field guides downstream commands (`/issue:plan`, `/issue:execute`):
57
57
 
58
- ```typescript
59
- interface SolutionTask {
60
- id: string;
61
- title: string;
62
- scope: string;
63
- action: string;
64
-
65
- // Phase 1: Implementation
66
- implementation: string[]; // Step-by-step implementation
67
- modification_points: { file: string; target: string; change: string }[];
68
-
69
- // Phase 2: Testing
70
- test: {
71
- unit?: string[]; // Unit test requirements
72
- integration?: string[]; // Integration test requirements
73
- commands?: string[]; // Test commands to run
74
- coverage_target?: number; // Minimum coverage %
75
- };
76
-
77
- // Phase 3: Regression
78
- regression: string[]; // Regression check commands/points
79
-
80
- // Phase 4: Acceptance
81
- acceptance: {
82
- criteria: string[]; // Testable acceptance criteria
83
- verification: string[]; // How to verify each criterion
84
- manual_checks?: string[]; // Manual verification if needed
85
- };
58
+ | Field | Options | Purpose |
59
+ |-------|---------|---------|
60
+ | `test_strategy` | `unit`, `integration`, `e2e`, `manual`, `auto` | Which test types to generate |
61
+ | `regression_scope` | `affected`, `related`, `full` | Which tests to run for regression |
62
+ | `acceptance_type` | `automated`, `manual`, `both` | How to verify completion |
63
+ | `commit_strategy` | `per-task`, `squash`, `atomic` | Commit granularity |
86
64
 
87
- // Phase 5: Commit
88
- commit: {
89
- type: 'feat' | 'fix' | 'refactor' | 'test' | 'docs' | 'chore';
90
- scope: string; // e.g., "auth", "api"
91
- message_template: string; // Commit message template
92
- breaking?: boolean;
93
- };
94
-
95
- depends_on: string[];
96
- executor: 'codex' | 'gemini' | 'agent' | 'auto';
97
- }
98
- ```
65
+ > **Note**: Task structure (SolutionTask) is defined in `/issue:plan` - see `.claude/commands/issue/plan.md`
99
66
 
100
67
  ## Usage
101
68
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: plan
3
3
  description: Batch plan issue resolution using issue-plan-agent (explore + plan closed-loop)
4
- argument-hint: "<issue-id>[,<issue-id>,...] [--batch-size 3]"
4
+ argument-hint: "<issue-id>[,<issue-id>,...] [--batch-size 3] --all-pending"
5
5
  allowed-tools: TodoWrite(*), Task(*), SlashCommand(*), AskUserQuestion(*), Bash(*), Read(*), Write(*)
6
6
  ---
7
7
 
@@ -9,13 +9,35 @@ allowed-tools: TodoWrite(*), Task(*), SlashCommand(*), AskUserQuestion(*), Bash(
9
9
 
10
10
  ## Overview
11
11
 
12
- Unified planning command using **issue-plan-agent** that combines exploration and planning into a single closed-loop workflow. The agent handles ACE semantic search, solution generation, and task breakdown.
12
+ Unified planning command using **issue-plan-agent** that combines exploration and planning into a single closed-loop workflow.
13
+
14
+ ## Output Requirements
15
+
16
+ **Generate Files:**
17
+ 1. `.workflow/issues/solutions/{issue-id}.jsonl` - Solution with tasks for each issue
18
+
19
+ **Return Summary:**
20
+ ```json
21
+ {
22
+ "bound": [{ "issue_id": "...", "solution_id": "...", "task_count": N }],
23
+ "pending_selection": [{ "issue_id": "...", "solutions": [...] }],
24
+ "conflicts": [{ "file": "...", "issues": [...] }]
25
+ }
26
+ ```
27
+
28
+ **Completion Criteria:**
29
+ - [ ] Solution file generated for each issue
30
+ - [ ] Single solution → auto-bound via `ccw issue bind`
31
+ - [ ] Multiple solutions → returned for user selection
32
+ - [ ] Tasks conform to schema: `cat .claude/workflows/cli-templates/schemas/issue-task-jsonl-schema.json`
33
+ - [ ] Each task has quantified `delivery_criteria`
34
+
35
+ ## Core Capabilities
13
36
 
14
- **Core capabilities:**
15
37
  - **Closed-loop agent**: issue-plan-agent combines explore + plan
16
38
  - Batch processing: 1 agent processes 1-3 issues
17
39
  - ACE semantic search integrated into planning
18
- - Solution with executable tasks and acceptance criteria
40
+ - Solution with executable tasks and delivery criteria
19
41
  - Automatic solution registration and binding
20
42
 
21
43
  ## Storage Structure (Flat JSONL)
@@ -75,120 +97,90 @@ Phase 4: Summary
75
97
 
76
98
  ## Implementation
77
99
 
78
- ### Phase 1: Issue Loading
100
+ ### Phase 1: Issue Loading (IDs Only)
79
101
 
80
102
  ```javascript
81
- // Parse input
82
- const issueIds = userInput.includes(',')
83
- ? userInput.split(',').map(s => s.trim())
84
- : [userInput.trim()];
85
-
86
- // Read issues.jsonl
87
- const issuesPath = '.workflow/issues/issues.jsonl';
88
- const allIssues = Bash(`cat "${issuesPath}" 2>/dev/null || echo ''`)
89
- .split('\n')
90
- .filter(line => line.trim())
91
- .map(line => JSON.parse(line));
92
-
93
- // Load and validate issues
94
- const issues = [];
95
- for (const id of issueIds) {
96
- let issue = allIssues.find(i => i.id === id);
97
-
98
- if (!issue) {
99
- console.log(`Issue ${id} not found. Creating...`);
100
- issue = {
101
- id,
102
- title: `Issue ${id}`,
103
- status: 'registered',
104
- priority: 3,
105
- context: '',
106
- created_at: new Date().toISOString(),
107
- updated_at: new Date().toISOString()
108
- };
109
- // Append to issues.jsonl
110
- Bash(`echo '${JSON.stringify(issue)}' >> "${issuesPath}"`);
111
- }
103
+ const batchSize = flags.batchSize || 3;
104
+ let issueIds = [];
105
+
106
+ if (flags.allPending) {
107
+ // Get pending issue IDs directly via CLI
108
+ const ids = Bash(`ccw issue list --status pending,registered --ids`).trim();
109
+ issueIds = ids ? ids.split('\n').filter(Boolean) : [];
112
110
 
113
- issues.push(issue);
111
+ if (issueIds.length === 0) {
112
+ console.log('No pending issues found.');
113
+ return;
114
+ }
115
+ console.log(`Found ${issueIds.length} pending issues`);
116
+ } else {
117
+ // Parse comma-separated issue IDs
118
+ issueIds = userInput.includes(',')
119
+ ? userInput.split(',').map(s => s.trim())
120
+ : [userInput.trim()];
121
+
122
+ // Create if not exists
123
+ for (const id of issueIds) {
124
+ Bash(`ccw issue init ${id} --title "Issue ${id}" 2>/dev/null || true`);
125
+ }
114
126
  }
115
127
 
116
128
  // Group into batches
117
- const batchSize = flags.batchSize || 3;
118
129
  const batches = [];
119
- for (let i = 0; i < issues.length; i += batchSize) {
120
- batches.push(issues.slice(i, i + batchSize));
130
+ for (let i = 0; i < issueIds.length; i += batchSize) {
131
+ batches.push(issueIds.slice(i, i + batchSize));
121
132
  }
122
133
 
134
+ console.log(`Processing ${issueIds.length} issues in ${batches.length} batch(es)`);
135
+
123
136
  TodoWrite({
124
- todos: batches.flatMap((batch, i) => [
125
- { content: `Plan batch ${i+1}`, status: 'pending', activeForm: `Planning batch ${i+1}` }
126
- ])
137
+ todos: batches.map((_, i) => ({
138
+ content: `Plan batch ${i+1}`,
139
+ status: 'pending',
140
+ activeForm: `Planning batch ${i+1}`
141
+ }))
127
142
  });
128
143
  ```
129
144
 
130
145
  ### Phase 2: Unified Explore + Plan (issue-plan-agent)
131
146
 
132
147
  ```javascript
148
+ Bash(`mkdir -p .workflow/issues/solutions`);
149
+ const pendingSelections = []; // Collect multi-solution issues for user selection
150
+
133
151
  for (const [batchIndex, batch] of batches.entries()) {
134
152
  updateTodo(`Plan batch ${batchIndex + 1}`, 'in_progress');
135
153
 
136
- // Build issue prompt for agent with lifecycle requirements
154
+ // Build minimal prompt - agent handles exploration, planning, and binding
137
155
  const issuePrompt = `
138
- ## Issues to Plan (Closed-Loop Tasks Required)
139
-
140
- ${batch.map((issue, i) => `
141
- ### Issue ${i + 1}: ${issue.id}
142
- **Title**: ${issue.title}
143
- **Context**: ${issue.context || 'No context provided'}
144
- **Affected Components**: ${issue.affected_components?.join(', ') || 'Not specified'}
145
-
146
- **Lifecycle Requirements**:
147
- - Test Strategy: ${issue.lifecycle_requirements?.test_strategy || 'auto'}
148
- - Regression Scope: ${issue.lifecycle_requirements?.regression_scope || 'affected'}
149
- - Commit Strategy: ${issue.lifecycle_requirements?.commit_strategy || 'per-task'}
150
- `).join('\n')}
151
-
152
- ## Project Root
153
- ${process.cwd()}
154
-
155
- ## Requirements - CLOSED-LOOP TASKS
156
-
157
- Each task MUST include ALL lifecycle phases:
158
-
159
- ### 1. Implementation
160
- - implementation: string[] (2-7 concrete steps)
161
- - modification_points: { file, target, change }[]
162
-
163
- ### 2. Test
164
- - test.unit: string[] (unit test requirements)
165
- - test.integration: string[] (integration test requirements if needed)
166
- - test.commands: string[] (actual test commands to run)
167
- - test.coverage_target: number (minimum coverage %)
168
-
169
- ### 3. Regression
170
- - regression: string[] (commands to run for regression check)
171
- - Based on issue's regression_scope setting
172
-
173
- ### 4. Acceptance
174
- - acceptance.criteria: string[] (testable acceptance criteria)
175
- - acceptance.verification: string[] (how to verify each criterion)
176
- - acceptance.manual_checks: string[] (manual checks if needed)
177
-
178
- ### 5. Commit
179
- - commit.type: feat|fix|refactor|test|docs|chore
180
- - commit.scope: string (module name)
181
- - commit.message_template: string (full commit message)
182
- - commit.breaking: boolean
183
-
184
- ## Additional Requirements
185
- 1. Use ACE semantic search (mcp__ace-tool__search_context) for exploration
186
- 2. Detect file conflicts if multiple issues
187
- 3. Generate executable test commands based on project's test framework
188
- 4. Infer commit scope from affected files
156
+ ## Plan Issues
157
+
158
+ **Issue IDs**: ${batch.join(', ')}
159
+ **Project Root**: ${process.cwd()}
160
+
161
+ ### Steps
162
+ 1. Fetch: \`ccw issue status <id> --json\`
163
+ 2. Explore (ACE) → Plan solution
164
+ 3. Register & bind: \`ccw issue bind <id> --solution <file>\`
165
+
166
+ ### Generate Files
167
+ \`.workflow/issues/solutions/{issue-id}.jsonl\` - Solution with tasks (schema: cat .claude/workflows/cli-templates/schemas/issue-task-jsonl-schema.json)
168
+
169
+ ### Binding Rules
170
+ - **Single solution**: Auto-bind via \`ccw issue bind <id> --solution <file>\`
171
+ - **Multiple solutions**: Register only, return for user selection
172
+
173
+ ### Return Summary
174
+ \`\`\`json
175
+ {
176
+ "bound": [{ "issue_id": "...", "solution_id": "...", "task_count": N }],
177
+ "pending_selection": [{ "issue_id": "...", "solutions": [{ "id": "...", "description": "...", "task_count": N }] }],
178
+ "conflicts": [{ "file": "...", "issues": [...] }]
179
+ }
180
+ \`\`\`
189
181
  `;
190
182
 
191
- // Launch issue-plan-agent (combines explore + plan)
183
+ // Launch issue-plan-agent - agent writes solutions directly
192
184
  const result = Task(
193
185
  subagent_type="issue-plan-agent",
194
186
  run_in_background=false,
@@ -196,200 +188,66 @@ Each task MUST include ALL lifecycle phases:
196
188
  prompt=issuePrompt
197
189
  );
198
190
 
199
- // Parse agent output
200
- const agentOutput = JSON.parse(result);
191
+ // Parse summary from agent
192
+ const summary = JSON.parse(result);
201
193
 
202
- // Register solutions for each issue (append to solutions/{issue-id}.jsonl)
203
- for (const item of agentOutput.solutions) {
204
- const solutionPath = `.workflow/issues/solutions/${item.issue_id}.jsonl`;
205
-
206
- // Ensure solutions directory exists
207
- Bash(`mkdir -p .workflow/issues/solutions`);
208
-
209
- // Append solution as new line
210
- Bash(`echo '${JSON.stringify(item.solution)}' >> "${solutionPath}"`);
194
+ // Display auto-bound solutions
195
+ for (const item of summary.bound || []) {
196
+ console.log(`✓ ${item.issue_id}: ${item.solution_id} (${item.task_count} tasks)`);
211
197
  }
212
198
 
213
- // Handle conflicts if any
214
- if (agentOutput.conflicts?.length > 0) {
215
- console.log(`\n⚠ File conflicts detected:`);
216
- agentOutput.conflicts.forEach(c => {
217
- console.log(` ${c.file}: ${c.issues.join(', ')} → suggested: ${c.suggested_order.join(' → ')}`);
218
- });
199
+ // Collect pending selections for Phase 3
200
+ pendingSelections.push(...(summary.pending_selection || []));
201
+
202
+ // Show conflicts
203
+ if (summary.conflicts?.length > 0) {
204
+ console.log(`⚠ Conflicts: ${summary.conflicts.map(c => c.file).join(', ')}`);
219
205
  }
220
206
 
221
207
  updateTodo(`Plan batch ${batchIndex + 1}`, 'completed');
222
208
  }
223
209
  ```
224
210
 
225
- ### Phase 3: Solution Binding
211
+ ### Phase 3: Multi-Solution Selection
226
212
 
227
213
  ```javascript
228
- // Re-read issues.jsonl
229
- let allIssuesUpdated = Bash(`cat "${issuesPath}"`)
230
- .split('\n')
231
- .filter(line => line.trim())
232
- .map(line => JSON.parse(line));
233
-
234
- for (const issue of issues) {
235
- const solPath = `.workflow/issues/solutions/${issue.id}.jsonl`;
236
- const solutions = Bash(`cat "${solPath}" 2>/dev/null || echo ''`)
237
- .split('\n')
238
- .filter(line => line.trim())
239
- .map(line => JSON.parse(line));
240
-
241
- if (solutions.length === 0) {
242
- console.log(`⚠ No solutions for ${issue.id}`);
243
- continue;
244
- }
245
-
246
- let selectedSolId;
247
-
248
- if (solutions.length === 1) {
249
- // Auto-bind single solution
250
- selectedSolId = solutions[0].id;
251
- console.log(`✓ Auto-bound ${selectedSolId} to ${issue.id} (${solutions[0].tasks?.length || 0} tasks)`);
252
- } else {
253
- // Multiple solutions - ask user
254
- const answer = AskUserQuestion({
255
- questions: [{
256
- question: `Select solution for ${issue.id}:`,
257
- header: issue.id,
258
- multiSelect: false,
259
- options: solutions.map(s => ({
260
- label: `${s.id}: ${s.description || 'Solution'}`,
261
- description: `${s.tasks?.length || 0} tasks`
262
- }))
263
- }]
264
- });
265
-
266
- selectedSolId = extractSelectedSolutionId(answer);
267
- console.log(`✓ Bound ${selectedSolId} to ${issue.id}`);
268
- }
269
-
270
- // Update issue in allIssuesUpdated
271
- const issueIndex = allIssuesUpdated.findIndex(i => i.id === issue.id);
272
- if (issueIndex !== -1) {
273
- allIssuesUpdated[issueIndex].bound_solution_id = selectedSolId;
274
- allIssuesUpdated[issueIndex].status = 'planned';
275
- allIssuesUpdated[issueIndex].planned_at = new Date().toISOString();
276
- allIssuesUpdated[issueIndex].updated_at = new Date().toISOString();
214
+ // Only handle issues where agent generated multiple solutions
215
+ if (pendingSelections.length > 0) {
216
+ const answer = AskUserQuestion({
217
+ questions: pendingSelections.map(({ issue_id, solutions }) => ({
218
+ question: `Select solution for ${issue_id}:`,
219
+ header: issue_id,
220
+ multiSelect: false,
221
+ options: solutions.map(s => ({
222
+ label: `${s.id} (${s.task_count} tasks)`,
223
+ description: s.description
224
+ }))
225
+ }))
226
+ });
227
+
228
+ // Bind user-selected solutions
229
+ for (const { issue_id } of pendingSelections) {
230
+ const selectedId = extractSelectedSolutionId(answer, issue_id);
231
+ if (selectedId) {
232
+ Bash(`ccw issue bind ${issue_id} ${selectedId}`);
233
+ console.log(`✓ ${issue_id}: ${selectedId} bound`);
234
+ }
277
235
  }
278
-
279
- // Mark solution as bound in solutions file
280
- const updatedSolutions = solutions.map(s => ({
281
- ...s,
282
- is_bound: s.id === selectedSolId,
283
- bound_at: s.id === selectedSolId ? new Date().toISOString() : s.bound_at
284
- }));
285
- Write(solPath, updatedSolutions.map(s => JSON.stringify(s)).join('\n'));
286
236
  }
287
-
288
- // Write updated issues.jsonl
289
- Write(issuesPath, allIssuesUpdated.map(i => JSON.stringify(i)).join('\n'));
290
237
  ```
291
238
 
292
239
  ### Phase 4: Summary
293
240
 
294
241
  ```javascript
295
- console.log(`
296
- ## Planning Complete
297
-
298
- **Issues Planned**: ${issues.length}
299
-
300
- ### Bound Solutions
301
- ${issues.map(i => {
302
- const issue = allIssuesUpdated.find(a => a.id === i.id);
303
- return issue?.bound_solution_id
304
- ? `✓ ${i.id}: ${issue.bound_solution_id}`
305
- : `○ ${i.id}: No solution bound`;
306
- }).join('\n')}
307
-
308
- ### Next Steps
309
- 1. Review: \`ccw issue status <issue-id>\`
310
- 2. Form queue: \`/issue:queue\`
311
- 3. Execute: \`/issue:execute\`
312
- `);
313
- ```
314
-
315
- ## Solution Format (Closed-Loop Tasks)
242
+ // Count planned issues via CLI
243
+ const plannedIds = Bash(`ccw issue list --status planned --ids`).trim();
244
+ const plannedCount = plannedIds ? plannedIds.split('\n').length : 0;
316
245
 
317
- Each solution line in `solutions/{issue-id}.jsonl`:
246
+ console.log(`
247
+ ## Done: ${issueIds.length} issues → ${plannedCount} planned
318
248
 
319
- ```json
320
- {
321
- "id": "SOL-20251226-001",
322
- "description": "Direct Implementation",
323
- "tasks": [
324
- {
325
- "id": "T1",
326
- "title": "Create auth middleware",
327
- "scope": "src/middleware/",
328
- "action": "Create",
329
- "description": "Create JWT validation middleware",
330
- "modification_points": [
331
- { "file": "src/middleware/auth.ts", "target": "new file", "change": "Create middleware" }
332
- ],
333
-
334
- "implementation": [
335
- "Create auth.ts file in src/middleware/",
336
- "Implement JWT token validation using jsonwebtoken",
337
- "Add error handling for invalid/expired tokens",
338
- "Export middleware function"
339
- ],
340
-
341
- "test": {
342
- "unit": [
343
- "Test valid token passes through",
344
- "Test invalid token returns 401",
345
- "Test expired token returns 401",
346
- "Test missing token returns 401"
347
- ],
348
- "commands": [
349
- "npm test -- --grep 'auth middleware'",
350
- "npm run test:coverage -- src/middleware/auth.ts"
351
- ],
352
- "coverage_target": 80
353
- },
354
-
355
- "regression": [
356
- "npm test -- --grep 'protected routes'",
357
- "npm run test:integration -- auth"
358
- ],
359
-
360
- "acceptance": {
361
- "criteria": [
362
- "Middleware validates JWT tokens successfully",
363
- "Returns 401 for invalid or missing tokens",
364
- "Passes decoded token to request context"
365
- ],
366
- "verification": [
367
- "curl -H 'Authorization: Bearer valid_token' /api/protected → 200",
368
- "curl /api/protected → 401",
369
- "curl -H 'Authorization: Bearer invalid' /api/protected → 401"
370
- ]
371
- },
372
-
373
- "commit": {
374
- "type": "feat",
375
- "scope": "auth",
376
- "message_template": "feat(auth): add JWT validation middleware\n\n- Implement token validation\n- Add error handling for invalid tokens\n- Export for route protection",
377
- "breaking": false
378
- },
379
-
380
- "depends_on": [],
381
- "estimated_minutes": 30,
382
- "executor": "codex"
383
- }
384
- ],
385
- "exploration_context": {
386
- "relevant_files": ["src/config/auth.ts"],
387
- "patterns": "Follow existing middleware pattern"
388
- },
389
- "is_bound": true,
390
- "created_at": "2025-12-26T10:00:00Z",
391
- "bound_at": "2025-12-26T10:05:00Z"
392
- }
249
+ Next: \`/issue:queue\` → \`/issue:execute\`
250
+ `);
393
251
  ```
394
252
 
395
253
  ## Error Handling
@@ -402,17 +260,6 @@ Each solution line in `solutions/{issue-id}.jsonl`:
402
260
  | User cancels selection | Skip issue, continue with others |
403
261
  | File conflicts | Agent detects and suggests resolution order |
404
262
 
405
- ## Agent Integration
406
-
407
- The command uses `issue-plan-agent` which:
408
- 1. Performs ACE semantic search per issue
409
- 2. Identifies modification points and patterns
410
- 3. Generates task breakdown with dependencies
411
- 4. Detects cross-issue file conflicts
412
- 5. Outputs solution JSON for registration
413
-
414
- See `.claude/agents/issue-plan-agent.md` for agent specification.
415
-
416
263
  ## Related Commands
417
264
 
418
265
  - `/issue:queue` - Form execution queue from bound solutions