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.
@@ -20,17 +20,23 @@ Interactive menu-driven interface for issue management using `ccw issue` CLI end
20
20
 
21
21
  ```bash
22
22
  # Core endpoints (ccw issue)
23
- ccw issue list # List all issues
24
- ccw issue list <id> --json # Get issue details
25
- ccw issue status <id> # Detailed status
26
- ccw issue init <id> --title "..." # Create issue
27
- ccw issue task <id> --title "..." # Add task
23
+ ccw issue list # List all issues
24
+ ccw issue list <id> --json # Get issue details
25
+ ccw issue status <id> # Detailed status
26
+ ccw issue init <id> --title "..." # Create issue
27
+ ccw issue task <id> --title "..." # Add task
28
+ ccw issue bind <id> <solution-id> # Bind solution
28
29
 
29
30
  # Queue management
30
- ccw issue queue # List queue
31
- ccw issue queue add <id> # Add to queue
32
- ccw issue next # Get next task
33
- ccw issue done <queue-id> # Complete task
31
+ ccw issue queue # List current queue
32
+ ccw issue queue add <id> # Add to queue
33
+ ccw issue queue list # Queue history
34
+ ccw issue queue switch <queue-id> # Switch queue
35
+ ccw issue queue archive # Archive queue
36
+ ccw issue queue delete <queue-id> # Delete queue
37
+ ccw issue next # Get next task
38
+ ccw issue done <queue-id> # Mark completed
39
+ ccw issue complete <item-id> # (legacy alias for done)
34
40
  ```
35
41
 
36
42
  ## Usage
@@ -49,7 +55,9 @@ ccw issue done <queue-id> # Complete task
49
55
 
50
56
  ## Implementation
51
57
 
52
- ### Phase 1: Entry Point
58
+ This command delegates to the `issue-manage` skill for detailed implementation.
59
+
60
+ ### Entry Point
53
61
 
54
62
  ```javascript
55
63
  const issueId = parseIssueId(userInput);
@@ -63,787 +71,30 @@ if (!action) {
63
71
  }
64
72
  ```
65
73
 
66
- ### Phase 2: Main Menu
67
-
68
- ```javascript
69
- async function showMainMenu(preselectedIssue = null) {
70
- // Fetch current issues summary
71
- const issuesResult = Bash('ccw issue list --json 2>/dev/null || echo "[]"');
72
- const issues = JSON.parse(issuesResult) || [];
73
-
74
- const queueResult = Bash('ccw issue status --json 2>/dev/null');
75
- const queueStatus = JSON.parse(queueResult || '{}');
76
-
77
- console.log(`
78
- ## Issue Management Dashboard
79
-
80
- **Total Issues**: ${issues.length}
81
- **Queue Status**: ${queueStatus.queue?.total_tasks || 0} tasks (${queueStatus.queue?.pending_count || 0} pending)
82
-
83
- ### Quick Stats
84
- - Registered: ${issues.filter(i => i.status === 'registered').length}
85
- - Planned: ${issues.filter(i => i.status === 'planned').length}
86
- - Executing: ${issues.filter(i => i.status === 'executing').length}
87
- - Completed: ${issues.filter(i => i.status === 'completed').length}
88
- `);
89
-
90
- const answer = AskUserQuestion({
91
- questions: [{
92
- question: 'What would you like to do?',
93
- header: 'Action',
94
- multiSelect: false,
95
- options: [
96
- { label: 'List Issues', description: 'Browse all issues with filters' },
97
- { label: 'View Issue', description: 'Detailed view of specific issue' },
98
- { label: 'Create Issue', description: 'Add new issue from text or GitHub' },
99
- { label: 'Edit Issue', description: 'Modify issue fields' },
100
- { label: 'Delete Issue', description: 'Remove issue(s)' },
101
- { label: 'Bulk Operations', description: 'Batch actions on multiple issues' }
102
- ]
103
- }]
104
- });
105
-
106
- const selected = parseAnswer(answer);
107
-
108
- switch (selected) {
109
- case 'List Issues':
110
- await listIssuesInteractive();
111
- break;
112
- case 'View Issue':
113
- await viewIssueInteractive(preselectedIssue);
114
- break;
115
- case 'Create Issue':
116
- await createIssueInteractive();
117
- break;
118
- case 'Edit Issue':
119
- await editIssueInteractive(preselectedIssue);
120
- break;
121
- case 'Delete Issue':
122
- await deleteIssueInteractive(preselectedIssue);
123
- break;
124
- case 'Bulk Operations':
125
- await bulkOperationsInteractive();
126
- break;
127
- }
128
- }
129
- ```
130
-
131
- ### Phase 3: List Issues
132
-
133
- ```javascript
134
- async function listIssuesInteractive() {
135
- // Ask for filter
136
- const filterAnswer = AskUserQuestion({
137
- questions: [{
138
- question: 'Filter issues by status?',
139
- header: 'Filter',
140
- multiSelect: true,
141
- options: [
142
- { label: 'All', description: 'Show all issues' },
143
- { label: 'Registered', description: 'New, unplanned issues' },
144
- { label: 'Planned', description: 'Issues with bound solutions' },
145
- { label: 'Queued', description: 'In execution queue' },
146
- { label: 'Executing', description: 'Currently being worked on' },
147
- { label: 'Completed', description: 'Finished issues' },
148
- { label: 'Failed', description: 'Failed issues' }
149
- ]
150
- }]
151
- });
152
-
153
- const filters = parseMultiAnswer(filterAnswer);
154
-
155
- // Fetch and filter issues
156
- const result = Bash('ccw issue list --json');
157
- let issues = JSON.parse(result) || [];
158
-
159
- if (!filters.includes('All')) {
160
- const statusMap = {
161
- 'Registered': 'registered',
162
- 'Planned': 'planned',
163
- 'Queued': 'queued',
164
- 'Executing': 'executing',
165
- 'Completed': 'completed',
166
- 'Failed': 'failed'
167
- };
168
- const allowedStatuses = filters.map(f => statusMap[f]).filter(Boolean);
169
- issues = issues.filter(i => allowedStatuses.includes(i.status));
170
- }
171
-
172
- if (issues.length === 0) {
173
- console.log('No issues found matching filters.');
174
- return showMainMenu();
175
- }
176
-
177
- // Display issues table
178
- console.log(`
179
- ## Issues (${issues.length})
180
-
181
- | ID | Status | Priority | Title |
182
- |----|--------|----------|-------|
183
- ${issues.map(i => `| ${i.id} | ${i.status} | P${i.priority} | ${i.title.substring(0, 40)} |`).join('\n')}
184
- `);
185
-
186
- // Ask for action on issue
187
- const actionAnswer = AskUserQuestion({
188
- questions: [{
189
- question: 'Select an issue to view/edit, or return to menu:',
190
- header: 'Select',
191
- multiSelect: false,
192
- options: [
193
- ...issues.slice(0, 10).map(i => ({
194
- label: i.id,
195
- description: i.title.substring(0, 50)
196
- })),
197
- { label: 'Back to Menu', description: 'Return to main menu' }
198
- ]
199
- }]
200
- });
201
-
202
- const selected = parseAnswer(actionAnswer);
203
-
204
- if (selected === 'Back to Menu') {
205
- return showMainMenu();
206
- }
207
-
208
- // View selected issue
209
- await viewIssueInteractive(selected);
210
- }
211
- ```
212
-
213
- ### Phase 4: View Issue
74
+ ### Main Menu Flow
214
75
 
215
- ```javascript
216
- async function viewIssueInteractive(issueId) {
217
- if (!issueId) {
218
- // Ask for issue ID
219
- const issues = JSON.parse(Bash('ccw issue list --json') || '[]');
220
-
221
- const idAnswer = AskUserQuestion({
222
- questions: [{
223
- question: 'Select issue to view:',
224
- header: 'Issue',
225
- multiSelect: false,
226
- options: issues.slice(0, 10).map(i => ({
227
- label: i.id,
228
- description: `${i.status} - ${i.title.substring(0, 40)}`
229
- }))
230
- }]
231
- });
232
-
233
- issueId = parseAnswer(idAnswer);
234
- }
235
-
236
- // Fetch detailed status
237
- const result = Bash(`ccw issue status ${issueId} --json`);
238
- const data = JSON.parse(result);
239
-
240
- const issue = data.issue;
241
- const solutions = data.solutions || [];
242
- const bound = data.bound;
243
-
244
- console.log(`
245
- ## Issue: ${issue.id}
76
+ 1. **Dashboard**: Fetch issues summary via `ccw issue list --json`
77
+ 2. **Menu**: Present action options via AskUserQuestion
78
+ 3. **Route**: Execute selected action (List/View/Edit/Delete/Bulk)
79
+ 4. **Loop**: Return to menu after each action
246
80
 
247
- **Title**: ${issue.title}
248
- **Status**: ${issue.status}
249
- **Priority**: P${issue.priority}
250
- **Created**: ${issue.created_at}
251
- **Updated**: ${issue.updated_at}
81
+ ### Available Actions
252
82
 
253
- ### Context
254
- ${issue.context || 'No context provided'}
83
+ | Action | Description | CLI Command |
84
+ |--------|-------------|-------------|
85
+ | List | Browse with filters | `ccw issue list --json` |
86
+ | View | Detail view | `ccw issue status <id> --json` |
87
+ | Edit | Modify fields | Update `issues.jsonl` |
88
+ | Delete | Remove issue | Clean up all related files |
89
+ | Bulk | Batch operations | Multi-select + batch update |
255
90
 
256
- ### Solutions (${solutions.length})
257
- ${solutions.length === 0 ? 'No solutions registered' :
258
- solutions.map(s => `- ${s.is_bound ? '◉' : '○'} ${s.id}: ${s.tasks?.length || 0} tasks`).join('\n')}
259
-
260
- ${bound ? `### Bound Solution: ${bound.id}\n**Tasks**: ${bound.tasks?.length || 0}` : ''}
261
- `);
262
-
263
- // Show tasks if bound solution exists
264
- if (bound?.tasks?.length > 0) {
265
- console.log(`
266
- ### Tasks
267
- | ID | Action | Scope | Title |
268
- |----|--------|-------|-------|
269
- ${bound.tasks.map(t => `| ${t.id} | ${t.action} | ${t.scope?.substring(0, 20) || '-'} | ${t.title.substring(0, 30)} |`).join('\n')}
270
- `);
271
- }
272
-
273
- // Action menu
274
- const actionAnswer = AskUserQuestion({
275
- questions: [{
276
- question: 'What would you like to do?',
277
- header: 'Action',
278
- multiSelect: false,
279
- options: [
280
- { label: 'Edit Issue', description: 'Modify issue fields' },
281
- { label: 'Plan Issue', description: 'Generate solution (/issue:plan)' },
282
- { label: 'Add to Queue', description: 'Queue bound solution tasks' },
283
- { label: 'View Queue', description: 'See queue status' },
284
- { label: 'Delete Issue', description: 'Remove this issue' },
285
- { label: 'Back to Menu', description: 'Return to main menu' }
286
- ]
287
- }]
288
- });
289
-
290
- const action = parseAnswer(actionAnswer);
291
-
292
- switch (action) {
293
- case 'Edit Issue':
294
- await editIssueInteractive(issueId);
295
- break;
296
- case 'Plan Issue':
297
- console.log(`Running: /issue:plan ${issueId}`);
298
- // Invoke plan skill
299
- break;
300
- case 'Add to Queue':
301
- Bash(`ccw issue queue add ${issueId}`);
302
- console.log(`✓ Added ${issueId} tasks to queue`);
303
- break;
304
- case 'View Queue':
305
- const queueOutput = Bash('ccw issue queue');
306
- console.log(queueOutput);
307
- break;
308
- case 'Delete Issue':
309
- await deleteIssueInteractive(issueId);
310
- break;
311
- default:
312
- return showMainMenu();
313
- }
314
- }
315
- ```
316
-
317
- ### Phase 5: Edit Issue
318
-
319
- ```javascript
320
- async function editIssueInteractive(issueId) {
321
- if (!issueId) {
322
- const issues = JSON.parse(Bash('ccw issue list --json') || '[]');
323
- const idAnswer = AskUserQuestion({
324
- questions: [{
325
- question: 'Select issue to edit:',
326
- header: 'Issue',
327
- multiSelect: false,
328
- options: issues.slice(0, 10).map(i => ({
329
- label: i.id,
330
- description: `${i.status} - ${i.title.substring(0, 40)}`
331
- }))
332
- }]
333
- });
334
- issueId = parseAnswer(idAnswer);
335
- }
336
-
337
- // Get current issue data
338
- const result = Bash(`ccw issue list ${issueId} --json`);
339
- const issueData = JSON.parse(result);
340
- const issue = issueData.issue || issueData;
341
-
342
- // Ask which field to edit
343
- const fieldAnswer = AskUserQuestion({
344
- questions: [{
345
- question: 'Which field to edit?',
346
- header: 'Field',
347
- multiSelect: false,
348
- options: [
349
- { label: 'Title', description: `Current: ${issue.title?.substring(0, 40)}` },
350
- { label: 'Priority', description: `Current: P${issue.priority}` },
351
- { label: 'Status', description: `Current: ${issue.status}` },
352
- { label: 'Context', description: 'Edit problem description' },
353
- { label: 'Labels', description: `Current: ${issue.labels?.join(', ') || 'none'}` },
354
- { label: 'Back', description: 'Return without changes' }
355
- ]
356
- }]
357
- });
358
-
359
- const field = parseAnswer(fieldAnswer);
360
-
361
- if (field === 'Back') {
362
- return viewIssueInteractive(issueId);
363
- }
364
-
365
- let updatePayload = {};
366
-
367
- switch (field) {
368
- case 'Title':
369
- const titleAnswer = AskUserQuestion({
370
- questions: [{
371
- question: 'Enter new title (or select current to keep):',
372
- header: 'Title',
373
- multiSelect: false,
374
- options: [
375
- { label: issue.title.substring(0, 50), description: 'Keep current title' }
376
- ]
377
- }]
378
- });
379
- const newTitle = parseAnswer(titleAnswer);
380
- if (newTitle && newTitle !== issue.title.substring(0, 50)) {
381
- updatePayload.title = newTitle;
382
- }
383
- break;
384
-
385
- case 'Priority':
386
- const priorityAnswer = AskUserQuestion({
387
- questions: [{
388
- question: 'Select priority:',
389
- header: 'Priority',
390
- multiSelect: false,
391
- options: [
392
- { label: 'P1 - Critical', description: 'Production blocking' },
393
- { label: 'P2 - High', description: 'Major functionality' },
394
- { label: 'P3 - Medium', description: 'Normal priority (default)' },
395
- { label: 'P4 - Low', description: 'Minor issues' },
396
- { label: 'P5 - Trivial', description: 'Nice to have' }
397
- ]
398
- }]
399
- });
400
- const priorityStr = parseAnswer(priorityAnswer);
401
- updatePayload.priority = parseInt(priorityStr.charAt(1));
402
- break;
403
-
404
- case 'Status':
405
- const statusAnswer = AskUserQuestion({
406
- questions: [{
407
- question: 'Select status:',
408
- header: 'Status',
409
- multiSelect: false,
410
- options: [
411
- { label: 'registered', description: 'New issue, not yet planned' },
412
- { label: 'planning', description: 'Solution being generated' },
413
- { label: 'planned', description: 'Solution bound, ready for queue' },
414
- { label: 'queued', description: 'In execution queue' },
415
- { label: 'executing', description: 'Currently being worked on' },
416
- { label: 'completed', description: 'All tasks finished' },
417
- { label: 'failed', description: 'Execution failed' },
418
- { label: 'paused', description: 'Temporarily on hold' }
419
- ]
420
- }]
421
- });
422
- updatePayload.status = parseAnswer(statusAnswer);
423
- break;
424
-
425
- case 'Context':
426
- console.log(`Current context:\n${issue.context || '(empty)'}\n`);
427
- const contextAnswer = AskUserQuestion({
428
- questions: [{
429
- question: 'Enter new context (problem description):',
430
- header: 'Context',
431
- multiSelect: false,
432
- options: [
433
- { label: 'Keep current', description: 'No changes' }
434
- ]
435
- }]
436
- });
437
- const newContext = parseAnswer(contextAnswer);
438
- if (newContext && newContext !== 'Keep current') {
439
- updatePayload.context = newContext;
440
- }
441
- break;
442
-
443
- case 'Labels':
444
- const labelsAnswer = AskUserQuestion({
445
- questions: [{
446
- question: 'Enter labels (comma-separated):',
447
- header: 'Labels',
448
- multiSelect: false,
449
- options: [
450
- { label: issue.labels?.join(',') || '', description: 'Keep current labels' }
451
- ]
452
- }]
453
- });
454
- const labelsStr = parseAnswer(labelsAnswer);
455
- if (labelsStr) {
456
- updatePayload.labels = labelsStr.split(',').map(l => l.trim());
457
- }
458
- break;
459
- }
460
-
461
- // Apply update if any
462
- if (Object.keys(updatePayload).length > 0) {
463
- // Read, update, write issues.jsonl
464
- const issuesPath = '.workflow/issues/issues.jsonl';
465
- const allIssues = Bash(`cat "${issuesPath}"`)
466
- .split('\n')
467
- .filter(line => line.trim())
468
- .map(line => JSON.parse(line));
469
-
470
- const idx = allIssues.findIndex(i => i.id === issueId);
471
- if (idx !== -1) {
472
- allIssues[idx] = {
473
- ...allIssues[idx],
474
- ...updatePayload,
475
- updated_at: new Date().toISOString()
476
- };
477
-
478
- Write(issuesPath, allIssues.map(i => JSON.stringify(i)).join('\n'));
479
- console.log(`✓ Updated ${issueId}: ${Object.keys(updatePayload).join(', ')}`);
480
- }
481
- }
482
-
483
- // Continue editing or return
484
- const continueAnswer = AskUserQuestion({
485
- questions: [{
486
- question: 'Continue editing?',
487
- header: 'Continue',
488
- multiSelect: false,
489
- options: [
490
- { label: 'Edit Another Field', description: 'Continue editing this issue' },
491
- { label: 'View Issue', description: 'See updated issue' },
492
- { label: 'Back to Menu', description: 'Return to main menu' }
493
- ]
494
- }]
495
- });
496
-
497
- const cont = parseAnswer(continueAnswer);
498
- if (cont === 'Edit Another Field') {
499
- await editIssueInteractive(issueId);
500
- } else if (cont === 'View Issue') {
501
- await viewIssueInteractive(issueId);
502
- } else {
503
- return showMainMenu();
504
- }
505
- }
506
- ```
91
+ ## Data Files
507
92
 
508
- ### Phase 6: Delete Issue
509
-
510
- ```javascript
511
- async function deleteIssueInteractive(issueId) {
512
- if (!issueId) {
513
- const issues = JSON.parse(Bash('ccw issue list --json') || '[]');
514
- const idAnswer = AskUserQuestion({
515
- questions: [{
516
- question: 'Select issue to delete:',
517
- header: 'Delete',
518
- multiSelect: false,
519
- options: issues.slice(0, 10).map(i => ({
520
- label: i.id,
521
- description: `${i.status} - ${i.title.substring(0, 40)}`
522
- }))
523
- }]
524
- });
525
- issueId = parseAnswer(idAnswer);
526
- }
527
-
528
- // Confirm deletion
529
- const confirmAnswer = AskUserQuestion({
530
- questions: [{
531
- question: `Delete issue ${issueId}? This will also remove associated solutions.`,
532
- header: 'Confirm',
533
- multiSelect: false,
534
- options: [
535
- { label: 'Delete', description: 'Permanently remove issue and solutions' },
536
- { label: 'Cancel', description: 'Keep issue' }
537
- ]
538
- }]
539
- });
540
-
541
- if (parseAnswer(confirmAnswer) !== 'Delete') {
542
- console.log('Deletion cancelled.');
543
- return showMainMenu();
544
- }
545
-
546
- // Remove from issues.jsonl
547
- const issuesPath = '.workflow/issues/issues.jsonl';
548
- const allIssues = Bash(`cat "${issuesPath}"`)
549
- .split('\n')
550
- .filter(line => line.trim())
551
- .map(line => JSON.parse(line));
552
-
553
- const filtered = allIssues.filter(i => i.id !== issueId);
554
- Write(issuesPath, filtered.map(i => JSON.stringify(i)).join('\n'));
555
-
556
- // Remove solutions file if exists
557
- const solPath = `.workflow/issues/solutions/${issueId}.jsonl`;
558
- Bash(`rm -f "${solPath}" 2>/dev/null || true`);
559
-
560
- // Remove from queue if present
561
- const queuePath = '.workflow/issues/queue.json';
562
- if (Bash(`test -f "${queuePath}" && echo exists`) === 'exists') {
563
- const queue = JSON.parse(Bash(`cat "${queuePath}"`));
564
- queue.queue = queue.queue.filter(q => q.issue_id !== issueId);
565
- Write(queuePath, JSON.stringify(queue, null, 2));
566
- }
567
-
568
- console.log(`✓ Deleted issue ${issueId}`);
569
- return showMainMenu();
570
- }
571
- ```
572
-
573
- ### Phase 7: Bulk Operations
574
-
575
- ```javascript
576
- async function bulkOperationsInteractive() {
577
- const bulkAnswer = AskUserQuestion({
578
- questions: [{
579
- question: 'Select bulk operation:',
580
- header: 'Bulk',
581
- multiSelect: false,
582
- options: [
583
- { label: 'Update Status', description: 'Change status of multiple issues' },
584
- { label: 'Update Priority', description: 'Change priority of multiple issues' },
585
- { label: 'Add Labels', description: 'Add labels to multiple issues' },
586
- { label: 'Delete Multiple', description: 'Remove multiple issues' },
587
- { label: 'Queue All Planned', description: 'Add all planned issues to queue' },
588
- { label: 'Retry All Failed', description: 'Reset all failed tasks to pending' },
589
- { label: 'Back', description: 'Return to main menu' }
590
- ]
591
- }]
592
- });
593
-
594
- const operation = parseAnswer(bulkAnswer);
595
-
596
- if (operation === 'Back') {
597
- return showMainMenu();
598
- }
599
-
600
- // Get issues for selection
601
- const allIssues = JSON.parse(Bash('ccw issue list --json') || '[]');
602
-
603
- if (operation === 'Queue All Planned') {
604
- const planned = allIssues.filter(i => i.status === 'planned' && i.bound_solution_id);
605
- for (const issue of planned) {
606
- Bash(`ccw issue queue add ${issue.id}`);
607
- console.log(`✓ Queued ${issue.id}`);
608
- }
609
- console.log(`\n✓ Queued ${planned.length} issues`);
610
- return showMainMenu();
611
- }
612
-
613
- if (operation === 'Retry All Failed') {
614
- Bash('ccw issue retry');
615
- console.log('✓ Reset all failed tasks to pending');
616
- return showMainMenu();
617
- }
618
-
619
- // Multi-select issues
620
- const selectAnswer = AskUserQuestion({
621
- questions: [{
622
- question: 'Select issues (multi-select):',
623
- header: 'Select',
624
- multiSelect: true,
625
- options: allIssues.slice(0, 15).map(i => ({
626
- label: i.id,
627
- description: `${i.status} - ${i.title.substring(0, 30)}`
628
- }))
629
- }]
630
- });
631
-
632
- const selectedIds = parseMultiAnswer(selectAnswer);
633
-
634
- if (selectedIds.length === 0) {
635
- console.log('No issues selected.');
636
- return showMainMenu();
637
- }
638
-
639
- // Execute bulk operation
640
- const issuesPath = '.workflow/issues/issues.jsonl';
641
- let issues = Bash(`cat "${issuesPath}"`)
642
- .split('\n')
643
- .filter(line => line.trim())
644
- .map(line => JSON.parse(line));
645
-
646
- switch (operation) {
647
- case 'Update Status':
648
- const statusAnswer = AskUserQuestion({
649
- questions: [{
650
- question: 'Select new status:',
651
- header: 'Status',
652
- multiSelect: false,
653
- options: [
654
- { label: 'registered', description: 'Reset to registered' },
655
- { label: 'paused', description: 'Pause issues' },
656
- { label: 'completed', description: 'Mark completed' }
657
- ]
658
- }]
659
- });
660
- const newStatus = parseAnswer(statusAnswer);
661
- issues = issues.map(i =>
662
- selectedIds.includes(i.id)
663
- ? { ...i, status: newStatus, updated_at: new Date().toISOString() }
664
- : i
665
- );
666
- break;
667
-
668
- case 'Update Priority':
669
- const prioAnswer = AskUserQuestion({
670
- questions: [{
671
- question: 'Select new priority:',
672
- header: 'Priority',
673
- multiSelect: false,
674
- options: [
675
- { label: 'P1', description: 'Critical' },
676
- { label: 'P2', description: 'High' },
677
- { label: 'P3', description: 'Medium' },
678
- { label: 'P4', description: 'Low' },
679
- { label: 'P5', description: 'Trivial' }
680
- ]
681
- }]
682
- });
683
- const newPrio = parseInt(parseAnswer(prioAnswer).charAt(1));
684
- issues = issues.map(i =>
685
- selectedIds.includes(i.id)
686
- ? { ...i, priority: newPrio, updated_at: new Date().toISOString() }
687
- : i
688
- );
689
- break;
690
-
691
- case 'Add Labels':
692
- const labelAnswer = AskUserQuestion({
693
- questions: [{
694
- question: 'Enter labels to add (comma-separated):',
695
- header: 'Labels',
696
- multiSelect: false,
697
- options: [
698
- { label: 'bug', description: 'Bug fix' },
699
- { label: 'feature', description: 'New feature' },
700
- { label: 'urgent', description: 'Urgent priority' }
701
- ]
702
- }]
703
- });
704
- const newLabels = parseAnswer(labelAnswer).split(',').map(l => l.trim());
705
- issues = issues.map(i =>
706
- selectedIds.includes(i.id)
707
- ? {
708
- ...i,
709
- labels: [...new Set([...(i.labels || []), ...newLabels])],
710
- updated_at: new Date().toISOString()
711
- }
712
- : i
713
- );
714
- break;
715
-
716
- case 'Delete Multiple':
717
- const confirmDelete = AskUserQuestion({
718
- questions: [{
719
- question: `Delete ${selectedIds.length} issues permanently?`,
720
- header: 'Confirm',
721
- multiSelect: false,
722
- options: [
723
- { label: 'Delete All', description: 'Remove selected issues' },
724
- { label: 'Cancel', description: 'Keep issues' }
725
- ]
726
- }]
727
- });
728
- if (parseAnswer(confirmDelete) === 'Delete All') {
729
- issues = issues.filter(i => !selectedIds.includes(i.id));
730
- // Clean up solutions
731
- for (const id of selectedIds) {
732
- Bash(`rm -f ".workflow/issues/solutions/${id}.jsonl" 2>/dev/null || true`);
733
- }
734
- } else {
735
- console.log('Deletion cancelled.');
736
- return showMainMenu();
737
- }
738
- break;
739
- }
740
-
741
- Write(issuesPath, issues.map(i => JSON.stringify(i)).join('\n'));
742
- console.log(`✓ Updated ${selectedIds.length} issues`);
743
- return showMainMenu();
744
- }
745
- ```
746
-
747
- ### Phase 8: Create Issue (Redirect)
748
-
749
- ```javascript
750
- async function createIssueInteractive() {
751
- const typeAnswer = AskUserQuestion({
752
- questions: [{
753
- question: 'Create issue from:',
754
- header: 'Source',
755
- multiSelect: false,
756
- options: [
757
- { label: 'GitHub URL', description: 'Import from GitHub issue' },
758
- { label: 'Text Description', description: 'Enter problem description' },
759
- { label: 'Quick Create', description: 'Just title and priority' }
760
- ]
761
- }]
762
- });
763
-
764
- const type = parseAnswer(typeAnswer);
765
-
766
- if (type === 'GitHub URL' || type === 'Text Description') {
767
- console.log('Use /issue:new for structured issue creation');
768
- console.log('Example: /issue:new https://github.com/org/repo/issues/123');
769
- return showMainMenu();
770
- }
771
-
772
- // Quick create
773
- const titleAnswer = AskUserQuestion({
774
- questions: [{
775
- question: 'Enter issue title:',
776
- header: 'Title',
777
- multiSelect: false,
778
- options: [
779
- { label: 'Authentication Bug', description: 'Example title' }
780
- ]
781
- }]
782
- });
783
-
784
- const title = parseAnswer(titleAnswer);
785
-
786
- const prioAnswer = AskUserQuestion({
787
- questions: [{
788
- question: 'Select priority:',
789
- header: 'Priority',
790
- multiSelect: false,
791
- options: [
792
- { label: 'P3 - Medium (Recommended)', description: 'Normal priority' },
793
- { label: 'P1 - Critical', description: 'Production blocking' },
794
- { label: 'P2 - High', description: 'Major functionality' }
795
- ]
796
- }]
797
- });
798
-
799
- const priority = parseInt(parseAnswer(prioAnswer).charAt(1));
800
-
801
- // Generate ID and create
802
- const id = `ISS-${Date.now()}`;
803
- Bash(`ccw issue init ${id} --title "${title}" --priority ${priority}`);
804
-
805
- console.log(`✓ Created issue ${id}`);
806
- await viewIssueInteractive(id);
807
- }
808
- ```
809
-
810
- ## Helper Functions
811
-
812
- ```javascript
813
- function parseAnswer(answer) {
814
- // Extract selected option from AskUserQuestion response
815
- if (typeof answer === 'string') return answer;
816
- if (answer.answers) {
817
- const values = Object.values(answer.answers);
818
- return values[0] || '';
819
- }
820
- return '';
821
- }
822
-
823
- function parseMultiAnswer(answer) {
824
- // Extract multiple selections
825
- if (typeof answer === 'string') return answer.split(',').map(s => s.trim());
826
- if (answer.answers) {
827
- const values = Object.values(answer.answers);
828
- return values.flatMap(v => v.split(',').map(s => s.trim()));
829
- }
830
- return [];
831
- }
832
-
833
- function parseFlags(input) {
834
- const flags = {};
835
- const matches = input.matchAll(/--(\w+)\s+([^\s-]+)/g);
836
- for (const match of matches) {
837
- flags[match[1]] = match[2];
838
- }
839
- return flags;
840
- }
841
-
842
- function parseIssueId(input) {
843
- const match = input.match(/^([A-Z]+-\d+|ISS-\d+|GH-\d+)/i);
844
- return match ? match[1] : null;
845
- }
846
- ```
93
+ | File | Purpose |
94
+ |------|---------|
95
+ | `.workflow/issues/issues.jsonl` | Issue records |
96
+ | `.workflow/issues/solutions/<id>.jsonl` | Solutions per issue |
97
+ | `.workflow/issues/queue.json` | Execution queue |
847
98
 
848
99
  ## Error Handling
849
100
 
@@ -853,7 +104,6 @@ function parseIssueId(input) {
853
104
  | Issue not found | Show available issues, ask for correction |
854
105
  | Invalid selection | Show error, re-prompt |
855
106
  | Write failure | Check permissions, show error |
856
- | Queue operation fails | Show ccw issue error, suggest fix |
857
107
 
858
108
  ## Related Commands
859
109
 
@@ -861,5 +111,3 @@ function parseIssueId(input) {
861
111
  - `/issue:plan` - Plan solution for issue
862
112
  - `/issue:queue` - Form execution queue
863
113
  - `/issue:execute` - Execute queued tasks
864
- - `ccw issue list` - CLI list command
865
- - `ccw issue status` - CLI status command