claude-code-workflow 6.3.13 → 6.3.16
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 +57 -103
- package/.claude/agents/issue-queue-agent.md +69 -120
- package/.claude/commands/issue/new.md +217 -473
- package/.claude/commands/issue/plan.md +76 -154
- package/.claude/commands/issue/queue.md +208 -259
- package/.claude/skills/issue-manage/SKILL.md +63 -22
- package/.claude/workflows/cli-templates/schemas/discovery-finding-schema.json +3 -3
- package/.claude/workflows/cli-templates/schemas/issues-jsonl-schema.json +3 -3
- package/.claude/workflows/cli-templates/schemas/queue-schema.json +0 -5
- package/.codex/prompts/issue-plan.md +16 -19
- package/.codex/prompts/issue-queue.md +0 -1
- package/README.md +1 -0
- package/ccw/dist/cli.d.ts.map +1 -1
- package/ccw/dist/cli.js +4 -1
- package/ccw/dist/cli.js.map +1 -1
- package/ccw/dist/commands/cli.d.ts +1 -0
- package/ccw/dist/commands/cli.d.ts.map +1 -1
- package/ccw/dist/commands/cli.js +59 -6
- package/ccw/dist/commands/cli.js.map +1 -1
- package/ccw/dist/commands/issue.d.ts +3 -1
- package/ccw/dist/commands/issue.d.ts.map +1 -1
- package/ccw/dist/commands/issue.js +383 -30
- package/ccw/dist/commands/issue.js.map +1 -1
- package/ccw/dist/core/routes/issue-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/issue-routes.js +77 -16
- package/ccw/dist/core/routes/issue-routes.js.map +1 -1
- package/ccw/dist/tools/cli-executor.d.ts.map +1 -1
- package/ccw/dist/tools/cli-executor.js +119 -4
- package/ccw/dist/tools/cli-executor.js.map +1 -1
- package/ccw/dist/tools/litellm-executor.d.ts +4 -0
- package/ccw/dist/tools/litellm-executor.d.ts.map +1 -1
- package/ccw/dist/tools/litellm-executor.js +54 -1
- package/ccw/dist/tools/litellm-executor.js.map +1 -1
- package/ccw/dist/tools/ui-generate-preview.d.ts +18 -0
- package/ccw/dist/tools/ui-generate-preview.d.ts.map +1 -1
- package/ccw/dist/tools/ui-generate-preview.js +26 -10
- package/ccw/dist/tools/ui-generate-preview.js.map +1 -1
- package/ccw/src/cli.ts +4 -1
- package/ccw/src/commands/cli.ts +64 -6
- package/ccw/src/commands/issue.ts +442 -34
- package/ccw/src/core/routes/issue-routes.ts +82 -16
- package/ccw/src/tools/cli-executor.ts +127 -4
- package/ccw/src/tools/litellm-executor.ts +107 -24
- package/ccw/src/tools/ui-generate-preview.js +60 -37
- package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/entities.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/config.py +25 -2
- package/codex-lens/src/codexlens/entities.py +5 -1
- package/codex-lens/src/codexlens/indexing/__pycache__/symbol_extractor.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/indexing/symbol_extractor.py +243 -243
- package/codex-lens/src/codexlens/parsers/__pycache__/factory.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/treesitter_parser.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/factory.py +256 -256
- package/codex-lens/src/codexlens/parsers/treesitter_parser.py +335 -335
- package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/chain_search.py +30 -1
- package/codex-lens/src/codexlens/semantic/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/embedder.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/reranker.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/embedder.py +6 -9
- package/codex-lens/src/codexlens/semantic/vector_store.py +271 -200
- package/codex-lens/src/codexlens/storage/__pycache__/dir_index.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/index_tree.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/sqlite_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/sqlite_store.py +184 -108
- package/package.json +6 -1
- package/.claude/commands/issue/manage.md +0 -113
|
@@ -1,565 +1,309 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: new
|
|
3
|
-
description: Create structured issue from GitHub URL or text description
|
|
4
|
-
argument-hint: "<github-url | text-description> [--priority 1-5]
|
|
5
|
-
allowed-tools: TodoWrite(*), Bash(*), Read(*),
|
|
3
|
+
description: Create structured issue from GitHub URL or text description
|
|
4
|
+
argument-hint: "<github-url | text-description> [--priority 1-5]"
|
|
5
|
+
allowed-tools: TodoWrite(*), Bash(*), Read(*), AskUserQuestion(*), mcp__ace-tool__search_context(*)
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Issue New Command (/issue:new)
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Core Principle
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
1. **GitHub Issue URL** - Fetches and parses issue content via `gh` CLI
|
|
14
|
-
2. **Text Description** - Parses natural language into structured fields
|
|
12
|
+
**Requirement Clarity Detection** → Ask only when needed
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
```
|
|
15
|
+
Clear Input (GitHub URL, structured text) → Direct creation
|
|
16
|
+
Unclear Input (vague description) → Minimal clarifying questions
|
|
17
|
+
```
|
|
17
18
|
|
|
18
|
-
## Issue Structure
|
|
19
|
+
## Issue Structure
|
|
19
20
|
|
|
20
21
|
```typescript
|
|
21
22
|
interface Issue {
|
|
22
23
|
id: string; // GH-123 or ISS-YYYYMMDD-HHMMSS
|
|
23
|
-
title: string;
|
|
24
|
-
status: 'registered'
|
|
24
|
+
title: string;
|
|
25
|
+
status: 'registered' | 'planned' | 'queued' | 'in_progress' | 'completed' | 'failed';
|
|
25
26
|
priority: number; // 1 (critical) to 5 (low)
|
|
26
|
-
context: string; // Problem description
|
|
27
|
-
source: 'github' | 'text' | 'discovery';
|
|
28
|
-
source_url?: string;
|
|
29
|
-
labels?: string[];
|
|
30
|
-
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
regression_scope: 'affected' | 'related' | 'full'; // Which tests to run
|
|
49
|
-
acceptance_type: 'automated' | 'manual' | 'both'; // How to verify
|
|
50
|
-
commit_strategy: 'per-task' | 'squash' | 'atomic'; // Commit granularity
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
// Metadata
|
|
54
|
-
bound_solution_id: null;
|
|
55
|
-
solution_count: 0;
|
|
27
|
+
context: string; // Problem description (single source of truth)
|
|
28
|
+
source: 'github' | 'text' | 'discovery';
|
|
29
|
+
source_url?: string;
|
|
30
|
+
labels?: string[];
|
|
31
|
+
|
|
32
|
+
// Optional structured fields
|
|
33
|
+
expected_behavior?: string;
|
|
34
|
+
actual_behavior?: string;
|
|
35
|
+
affected_components?: string[];
|
|
36
|
+
|
|
37
|
+
// Feedback history (failures + human clarifications)
|
|
38
|
+
feedback?: {
|
|
39
|
+
type: 'failure' | 'clarification' | 'rejection';
|
|
40
|
+
stage: string; // new/plan/execute
|
|
41
|
+
content: string;
|
|
42
|
+
created_at: string;
|
|
43
|
+
}[];
|
|
44
|
+
|
|
45
|
+
// Solution binding
|
|
46
|
+
bound_solution_id: string | null;
|
|
47
|
+
|
|
48
|
+
// Timestamps
|
|
56
49
|
created_at: string;
|
|
57
50
|
updated_at: string;
|
|
58
51
|
}
|
|
59
52
|
```
|
|
60
53
|
|
|
61
|
-
##
|
|
62
|
-
|
|
63
|
-
The `lifecycle_requirements` field guides downstream commands (`/issue:plan`, `/issue:execute`):
|
|
64
|
-
|
|
65
|
-
| Field | Options | Purpose |
|
|
66
|
-
|-------|---------|---------|
|
|
67
|
-
| `test_strategy` | `unit`, `integration`, `e2e`, `manual`, `auto` | Which test types to generate |
|
|
68
|
-
| `regression_scope` | `affected`, `related`, `full` | Which tests to run for regression |
|
|
69
|
-
| `acceptance_type` | `automated`, `manual`, `both` | How to verify completion |
|
|
70
|
-
| `commit_strategy` | `per-task`, `squash`, `atomic` | Commit granularity |
|
|
71
|
-
|
|
72
|
-
> **Note**: Task structure (SolutionTask) is defined in `/issue:plan` - see `.claude/commands/issue/plan.md`
|
|
73
|
-
|
|
74
|
-
## Usage
|
|
54
|
+
## Quick Reference
|
|
75
55
|
|
|
76
56
|
```bash
|
|
77
|
-
#
|
|
57
|
+
# Clear inputs - direct creation
|
|
78
58
|
/issue:new https://github.com/owner/repo/issues/123
|
|
59
|
+
/issue:new "Login fails with special chars. Expected: success. Actual: 500 error"
|
|
79
60
|
|
|
80
|
-
#
|
|
81
|
-
/issue:new "
|
|
82
|
-
|
|
83
|
-
# With options
|
|
84
|
-
/issue:new <url-or-text> --priority 2 --labels "bug,auth"
|
|
61
|
+
# Vague input - will ask clarifying questions
|
|
62
|
+
/issue:new "something wrong with auth"
|
|
85
63
|
```
|
|
86
64
|
|
|
87
65
|
## Implementation
|
|
88
66
|
|
|
89
|
-
### Phase 1: Input Detection
|
|
67
|
+
### Phase 1: Input Analysis & Clarity Detection
|
|
90
68
|
|
|
91
69
|
```javascript
|
|
92
70
|
const input = userInput.trim();
|
|
93
|
-
const flags = parseFlags(userInput); // --priority
|
|
71
|
+
const flags = parseFlags(userInput); // --priority
|
|
94
72
|
|
|
95
|
-
// Detect input type
|
|
73
|
+
// Detect input type and clarity
|
|
96
74
|
const isGitHubUrl = input.match(/github\.com\/[\w-]+\/[\w-]+\/issues\/\d+/);
|
|
97
|
-
const isGitHubShort = input.match(/^#(\d+)$/);
|
|
75
|
+
const isGitHubShort = input.match(/^#(\d+)$/);
|
|
76
|
+
const hasStructure = input.match(/(expected|actual|affects|steps):/i);
|
|
98
77
|
|
|
99
|
-
|
|
78
|
+
// Clarity score: 0-3
|
|
79
|
+
let clarityScore = 0;
|
|
80
|
+
if (isGitHubUrl || isGitHubShort) clarityScore = 3; // GitHub = fully clear
|
|
81
|
+
else if (hasStructure) clarityScore = 2; // Structured text = clear
|
|
82
|
+
else if (input.length > 50) clarityScore = 1; // Long text = somewhat clear
|
|
83
|
+
else clarityScore = 0; // Vague
|
|
100
84
|
|
|
101
|
-
|
|
102
|
-
// GitHub issue - fetch via gh CLI
|
|
103
|
-
issueData = await fetchGitHubIssue(input);
|
|
104
|
-
} else {
|
|
105
|
-
// Text description - parse structure
|
|
106
|
-
issueData = await parseTextDescription(input);
|
|
107
|
-
}
|
|
85
|
+
let issueData = {};
|
|
108
86
|
```
|
|
109
87
|
|
|
110
|
-
### Phase 2: GitHub
|
|
88
|
+
### Phase 2: Data Extraction (GitHub or Text)
|
|
111
89
|
|
|
112
90
|
```javascript
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
issueRef = `${match[1]}/${match[2]}#${match[3]}`;
|
|
121
|
-
} else {
|
|
122
|
-
// #123 format - use current repo
|
|
123
|
-
issueRef = urlOrNumber.replace('#', '');
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Fetch via gh CLI
|
|
127
|
-
const result = Bash(`gh issue view ${issueRef} --json number,title,body,labels,state,url`);
|
|
128
|
-
const ghIssue = JSON.parse(result);
|
|
129
|
-
|
|
130
|
-
// Parse body for structure
|
|
131
|
-
const parsed = parseIssueBody(ghIssue.body);
|
|
132
|
-
|
|
133
|
-
return {
|
|
134
|
-
id: `GH-${ghIssue.number}`,
|
|
135
|
-
title: ghIssue.title,
|
|
91
|
+
if (isGitHubUrl || isGitHubShort) {
|
|
92
|
+
// GitHub - fetch via gh CLI
|
|
93
|
+
const result = Bash(`gh issue view ${extractIssueRef(input)} --json number,title,body,labels,url`);
|
|
94
|
+
const gh = JSON.parse(result);
|
|
95
|
+
issueData = {
|
|
96
|
+
id: `GH-${gh.number}`,
|
|
97
|
+
title: gh.title,
|
|
136
98
|
source: 'github',
|
|
137
|
-
source_url:
|
|
138
|
-
labels:
|
|
139
|
-
context:
|
|
140
|
-
...
|
|
99
|
+
source_url: gh.url,
|
|
100
|
+
labels: gh.labels.map(l => l.name),
|
|
101
|
+
context: gh.body?.substring(0, 500) || gh.title,
|
|
102
|
+
...parseMarkdownBody(gh.body)
|
|
103
|
+
};
|
|
104
|
+
} else {
|
|
105
|
+
// Text description
|
|
106
|
+
issueData = {
|
|
107
|
+
id: `ISS-${new Date().toISOString().replace(/[-:T]/g, '').slice(0, 14)}`,
|
|
108
|
+
source: 'text',
|
|
109
|
+
...parseTextDescription(input)
|
|
141
110
|
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function parseIssueBody(body) {
|
|
145
|
-
// Extract structured sections from markdown body
|
|
146
|
-
const sections = {};
|
|
147
|
-
|
|
148
|
-
// Problem/Description
|
|
149
|
-
const problemMatch = body.match(/##?\s*(problem|description|issue)[:\s]*([\s\S]*?)(?=##|$)/i);
|
|
150
|
-
if (problemMatch) sections.problem_statement = problemMatch[2].trim();
|
|
151
|
-
|
|
152
|
-
// Expected behavior
|
|
153
|
-
const expectedMatch = body.match(/##?\s*(expected|should)[:\s]*([\s\S]*?)(?=##|$)/i);
|
|
154
|
-
if (expectedMatch) sections.expected_behavior = expectedMatch[2].trim();
|
|
155
|
-
|
|
156
|
-
// Actual behavior
|
|
157
|
-
const actualMatch = body.match(/##?\s*(actual|current)[:\s]*([\s\S]*?)(?=##|$)/i);
|
|
158
|
-
if (actualMatch) sections.actual_behavior = actualMatch[2].trim();
|
|
159
|
-
|
|
160
|
-
// Steps to reproduce
|
|
161
|
-
const stepsMatch = body.match(/##?\s*(steps|reproduce)[:\s]*([\s\S]*?)(?=##|$)/i);
|
|
162
|
-
if (stepsMatch) {
|
|
163
|
-
const stepsText = stepsMatch[2].trim();
|
|
164
|
-
sections.reproduction_steps = stepsText
|
|
165
|
-
.split('\n')
|
|
166
|
-
.filter(line => line.match(/^\s*[\d\-\*]/))
|
|
167
|
-
.map(line => line.replace(/^\s*[\d\.\-\*]\s*/, '').trim());
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Affected components (from file references)
|
|
171
|
-
const fileMatches = body.match(/`[^`]*\.(ts|js|tsx|jsx|py|go|rs)[^`]*`/g);
|
|
172
|
-
if (fileMatches) {
|
|
173
|
-
sections.affected_components = [...new Set(fileMatches.map(f => f.replace(/`/g, '')))];
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Fallback: use entire body as problem statement
|
|
177
|
-
if (!sections.problem_statement) {
|
|
178
|
-
sections.problem_statement = body.substring(0, 500);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return sections;
|
|
182
111
|
}
|
|
183
112
|
```
|
|
184
113
|
|
|
185
|
-
### Phase 3:
|
|
114
|
+
### Phase 3: Lightweight Context Hint (Conditional)
|
|
186
115
|
|
|
187
116
|
```javascript
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
// Pattern: "Title. Description. Expected: X. Actual: Y. Affects: files"
|
|
205
|
-
const sentences = text.split(/\.(?=\s|$)/);
|
|
206
|
-
|
|
207
|
-
// First sentence as title
|
|
208
|
-
result.title = sentences[0]?.trim() || 'Untitled Issue';
|
|
209
|
-
|
|
210
|
-
// Look for keywords
|
|
211
|
-
for (const sentence of sentences) {
|
|
212
|
-
const s = sentence.trim();
|
|
213
|
-
|
|
214
|
-
if (s.match(/^expected:?\s*/i)) {
|
|
215
|
-
result.expected_behavior = s.replace(/^expected:?\s*/i, '');
|
|
216
|
-
} else if (s.match(/^actual:?\s*/i)) {
|
|
217
|
-
result.actual_behavior = s.replace(/^actual:?\s*/i, '');
|
|
218
|
-
} else if (s.match(/^affects?:?\s*/i)) {
|
|
219
|
-
const components = s.replace(/^affects?:?\s*/i, '').split(/[,\s]+/);
|
|
220
|
-
result.affected_components = components.filter(c => c.includes('/') || c.includes('.'));
|
|
221
|
-
} else if (s.match(/^steps?:?\s*/i)) {
|
|
222
|
-
result.reproduction_steps = s.replace(/^steps?:?\s*/i, '').split(/[,;]/);
|
|
223
|
-
} else if (!result.problem_statement && s.length > 10) {
|
|
224
|
-
result.problem_statement = s;
|
|
117
|
+
// ACE search ONLY for medium clarity (1-2) AND missing components
|
|
118
|
+
// Skip for: GitHub (has context), vague (needs clarification first)
|
|
119
|
+
// Note: Deep exploration happens in /issue:plan, this is just a quick hint
|
|
120
|
+
|
|
121
|
+
if (clarityScore >= 1 && clarityScore <= 2 && !issueData.affected_components?.length) {
|
|
122
|
+
const keywords = extractKeywords(issueData.context);
|
|
123
|
+
|
|
124
|
+
if (keywords.length >= 2) {
|
|
125
|
+
try {
|
|
126
|
+
const aceResult = mcp__ace-tool__search_context({
|
|
127
|
+
project_root_path: process.cwd(),
|
|
128
|
+
query: keywords.slice(0, 3).join(' ')
|
|
129
|
+
});
|
|
130
|
+
issueData.affected_components = aceResult.files?.slice(0, 3) || [];
|
|
131
|
+
} catch {
|
|
132
|
+
// ACE failure is non-blocking
|
|
225
133
|
}
|
|
226
134
|
}
|
|
227
|
-
|
|
228
|
-
// Fallback problem statement
|
|
229
|
-
if (!result.problem_statement) {
|
|
230
|
-
result.problem_statement = text.substring(0, 300);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return result;
|
|
234
135
|
}
|
|
235
136
|
```
|
|
236
137
|
|
|
237
|
-
### Phase 4:
|
|
138
|
+
### Phase 4: Conditional Clarification (Only if Unclear)
|
|
238
139
|
|
|
239
140
|
```javascript
|
|
240
|
-
//
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
{
|
|
244
|
-
question: '
|
|
245
|
-
header: '
|
|
246
|
-
multiSelect: false,
|
|
247
|
-
options: [
|
|
248
|
-
{ label: 'auto', description: 'Auto-detect based on affected files (Recommended)' },
|
|
249
|
-
{ label: 'unit', description: 'Unit tests only' },
|
|
250
|
-
{ label: 'integration', description: 'Integration tests' },
|
|
251
|
-
{ label: 'e2e', description: 'End-to-end tests' },
|
|
252
|
-
{ label: 'manual', description: 'Manual testing only' }
|
|
253
|
-
]
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
question: 'Regression scope?',
|
|
257
|
-
header: 'Regression',
|
|
258
|
-
multiSelect: false,
|
|
259
|
-
options: [
|
|
260
|
-
{ label: 'affected', description: 'Only affected module tests (Recommended)' },
|
|
261
|
-
{ label: 'related', description: 'Affected + dependent modules' },
|
|
262
|
-
{ label: 'full', description: 'Full test suite' }
|
|
263
|
-
]
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
question: 'Commit strategy?',
|
|
267
|
-
header: 'Commit',
|
|
141
|
+
// ONLY ask questions if clarity is low - simple open-ended prompt
|
|
142
|
+
if (clarityScore < 2 && (!issueData.context || issueData.context.length < 20)) {
|
|
143
|
+
const answer = AskUserQuestion({
|
|
144
|
+
questions: [{
|
|
145
|
+
question: 'Please describe the issue in more detail:',
|
|
146
|
+
header: 'Clarify',
|
|
268
147
|
multiSelect: false,
|
|
269
148
|
options: [
|
|
270
|
-
{ label: '
|
|
271
|
-
{ label: 'atomic', description: 'Single commit for entire issue' },
|
|
272
|
-
{ label: 'squash', description: 'Squash at the end' }
|
|
149
|
+
{ label: 'Provide details', description: 'Describe what, where, and expected behavior' }
|
|
273
150
|
]
|
|
274
|
-
}
|
|
275
|
-
]
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
const lifecycle = {
|
|
279
|
-
test_strategy: lifecycleAnswer.test || 'auto',
|
|
280
|
-
regression_scope: lifecycleAnswer.regression || 'affected',
|
|
281
|
-
acceptance_type: 'automated',
|
|
282
|
-
commit_strategy: lifecycleAnswer.commit || 'per-task'
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
issueData.lifecycle_requirements = lifecycle;
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
### Phase 4.5: Follow-up Questions (Intelligent Suggestions)
|
|
289
|
-
|
|
290
|
-
```javascript
|
|
291
|
-
// Analyze parsed data and suggest follow-up questions for missing/unclear fields
|
|
292
|
-
const suggestions = [];
|
|
293
|
-
|
|
294
|
-
// Check for missing critical fields
|
|
295
|
-
if (!issueData.expected_behavior) {
|
|
296
|
-
suggestions.push({
|
|
297
|
-
field: 'expected_behavior',
|
|
298
|
-
question: 'What is the expected behavior?',
|
|
299
|
-
hint: 'Describe what should happen when working correctly'
|
|
151
|
+
}]
|
|
300
152
|
});
|
|
301
|
-
}
|
|
302
153
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
154
|
+
// Use custom text input (via "Other")
|
|
155
|
+
if (answer.customText) {
|
|
156
|
+
issueData.context = answer.customText;
|
|
157
|
+
issueData.title = answer.customText.split(/[.\n]/)[0].substring(0, 60);
|
|
158
|
+
issueData.feedback = [{
|
|
159
|
+
type: 'clarification',
|
|
160
|
+
stage: 'new',
|
|
161
|
+
content: answer.customText,
|
|
162
|
+
created_at: new Date().toISOString()
|
|
163
|
+
}];
|
|
164
|
+
}
|
|
309
165
|
}
|
|
166
|
+
```
|
|
310
167
|
|
|
311
|
-
|
|
312
|
-
suggestions.push({
|
|
313
|
-
field: 'affected_components',
|
|
314
|
-
question: 'Which files or modules are affected?',
|
|
315
|
-
hint: 'e.g., src/auth/login.ts, src/api/users.ts'
|
|
316
|
-
});
|
|
317
|
-
}
|
|
168
|
+
### Phase 5: Create Issue
|
|
318
169
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
field: 'reproduction_steps',
|
|
322
|
-
question: 'How can this issue be reproduced?',
|
|
323
|
-
hint: 'Step-by-step instructions to trigger the issue'
|
|
324
|
-
});
|
|
325
|
-
}
|
|
170
|
+
**Summary Display:**
|
|
171
|
+
- Show ID, title, source, affected files (if any)
|
|
326
172
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
if (suggestions.length > 0) {
|
|
330
|
-
console.log(`
|
|
331
|
-
## Suggested Clarifications
|
|
173
|
+
**Confirmation** (only for vague inputs, clarityScore < 2):
|
|
174
|
+
- Use `AskUserQuestion` to confirm before creation
|
|
332
175
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
176
|
+
**Issue Creation** (via CLI endpoint):
|
|
177
|
+
```bash
|
|
178
|
+
ccw issue create --data '{"title":"...", "context":"...", "priority":3, ...}'
|
|
179
|
+
```
|
|
336
180
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
{ label: 'Add details', description: 'Provide clarifications for suggested questions' },
|
|
344
|
-
{ label: 'Skip', description: 'Continue without additional details (Recommended)' }
|
|
345
|
-
]
|
|
346
|
-
}]
|
|
347
|
-
});
|
|
181
|
+
**CLI Endpoint Features:**
|
|
182
|
+
| Feature | Description |
|
|
183
|
+
|---------|-------------|
|
|
184
|
+
| Auto-increment ID | `ISS-YYYYMMDD-NNN` (e.g., `ISS-20251229-001`) |
|
|
185
|
+
| Trailing newline | Proper JSONL format, no corruption |
|
|
186
|
+
| JSON output | Returns created issue with all fields |
|
|
348
187
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
const actualMatch = userNotes.match(/actual:\s*([^|]+)/i);
|
|
368
|
-
const filesMatch = userNotes.match(/files?:\s*([^|]+)/i);
|
|
369
|
-
|
|
370
|
-
if (expectedMatch && !issueData.expected_behavior) {
|
|
371
|
-
issueData.expected_behavior = expectedMatch[1].trim();
|
|
372
|
-
}
|
|
373
|
-
if (actualMatch && !issueData.actual_behavior) {
|
|
374
|
-
issueData.actual_behavior = actualMatch[1].trim();
|
|
375
|
-
}
|
|
376
|
-
if (filesMatch && !issueData.affected_components?.length) {
|
|
377
|
-
issueData.affected_components = filesMatch[1].split(/[,\s]+/).filter(f => f.includes('/') || f.includes('.'));
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
188
|
+
**Example:**
|
|
189
|
+
```bash
|
|
190
|
+
# Create issue via CLI
|
|
191
|
+
ccw issue create --data '{
|
|
192
|
+
"title": "Login fails with special chars",
|
|
193
|
+
"context": "500 error when password contains quotes",
|
|
194
|
+
"priority": 2,
|
|
195
|
+
"source": "text",
|
|
196
|
+
"expected_behavior": "Login succeeds",
|
|
197
|
+
"actual_behavior": "500 Internal Server Error"
|
|
198
|
+
}'
|
|
199
|
+
|
|
200
|
+
# Output (JSON)
|
|
201
|
+
{
|
|
202
|
+
"id": "ISS-20251229-001",
|
|
203
|
+
"title": "Login fails with special chars",
|
|
204
|
+
"status": "registered",
|
|
205
|
+
...
|
|
381
206
|
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Completion:**
|
|
210
|
+
- Display created issue ID
|
|
211
|
+
- Show next step: `/issue:plan <id>`
|
|
382
212
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
213
|
+
## Execution Flow
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
Phase 1: Input Analysis
|
|
217
|
+
└─ Detect clarity score (GitHub URL? Structured text? Keywords?)
|
|
218
|
+
|
|
219
|
+
Phase 2: Data Extraction (branched by clarity)
|
|
220
|
+
┌────────────┬─────────────────┬──────────────┐
|
|
221
|
+
│ Score 3 │ Score 1-2 │ Score 0 │
|
|
222
|
+
│ GitHub │ Text + ACE │ Vague │
|
|
223
|
+
├────────────┼─────────────────┼──────────────┤
|
|
224
|
+
│ gh CLI │ Parse struct │ AskQuestion │
|
|
225
|
+
│ → parse │ + quick hint │ (1 question) │
|
|
226
|
+
│ │ (3 files max) │ → feedback │
|
|
227
|
+
└────────────┴─────────────────┴──────────────┘
|
|
228
|
+
|
|
229
|
+
Phase 3: Create Issue
|
|
230
|
+
├─ Score ≥ 2: Direct creation
|
|
231
|
+
└─ Score < 2: Confirm first → Create
|
|
232
|
+
|
|
233
|
+
Note: Deep exploration & lifecycle deferred to /issue:plan
|
|
388
234
|
```
|
|
389
235
|
|
|
390
|
-
|
|
236
|
+
## Helper Functions
|
|
391
237
|
|
|
392
238
|
```javascript
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
### Problem Statement
|
|
402
|
-
${issueData.problem_statement}
|
|
403
|
-
|
|
404
|
-
${issueData.expected_behavior ? `### Expected Behavior\n${issueData.expected_behavior}\n` : ''}
|
|
405
|
-
${issueData.actual_behavior ? `### Actual Behavior\n${issueData.actual_behavior}\n` : ''}
|
|
406
|
-
${issueData.affected_components?.length ? `### Affected Components\n${issueData.affected_components.map(c => `- ${c}`).join('\n')}\n` : ''}
|
|
407
|
-
${issueData.reproduction_steps?.length ? `### Reproduction Steps\n${issueData.reproduction_steps.map((s, i) => `${i+1}. ${s}`).join('\n')}\n` : ''}
|
|
408
|
-
|
|
409
|
-
### Lifecycle Configuration
|
|
410
|
-
- **Test Strategy**: ${lifecycle.test_strategy}
|
|
411
|
-
- **Regression Scope**: ${lifecycle.regression_scope}
|
|
412
|
-
- **Commit Strategy**: ${lifecycle.commit_strategy}
|
|
413
|
-
`);
|
|
414
|
-
|
|
415
|
-
// Ask user to confirm or edit
|
|
416
|
-
const answer = AskUserQuestion({
|
|
417
|
-
questions: [{
|
|
418
|
-
question: 'Create this issue?',
|
|
419
|
-
header: 'Confirm',
|
|
420
|
-
multiSelect: false,
|
|
421
|
-
options: [
|
|
422
|
-
{ label: 'Create', description: 'Save issue to issues.jsonl' },
|
|
423
|
-
{ label: 'Edit Title', description: 'Modify the issue title' },
|
|
424
|
-
{ label: 'Edit Priority', description: 'Change priority (1-5)' },
|
|
425
|
-
{ label: 'Cancel', description: 'Discard and exit' }
|
|
426
|
-
]
|
|
427
|
-
}]
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
if (answer.includes('Cancel')) {
|
|
431
|
-
console.log('Issue creation cancelled.');
|
|
432
|
-
return;
|
|
239
|
+
function extractKeywords(text) {
|
|
240
|
+
const stopWords = new Set(['the', 'a', 'an', 'is', 'are', 'was', 'were', 'not', 'with']);
|
|
241
|
+
return text
|
|
242
|
+
.toLowerCase()
|
|
243
|
+
.split(/\W+/)
|
|
244
|
+
.filter(w => w.length > 3 && !stopWords.has(w))
|
|
245
|
+
.slice(0, 5);
|
|
433
246
|
}
|
|
434
247
|
|
|
435
|
-
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
if (
|
|
448
|
-
|
|
248
|
+
function parseTextDescription(text) {
|
|
249
|
+
const result = { title: '', context: '' };
|
|
250
|
+
const sentences = text.split(/\.(?=\s|$)/);
|
|
251
|
+
|
|
252
|
+
result.title = sentences[0]?.trim().substring(0, 60) || 'Untitled';
|
|
253
|
+
result.context = text.substring(0, 500);
|
|
254
|
+
|
|
255
|
+
// Extract structured fields if present
|
|
256
|
+
const expected = text.match(/expected:?\s*([^.]+)/i);
|
|
257
|
+
const actual = text.match(/actual:?\s*([^.]+)/i);
|
|
258
|
+
const affects = text.match(/affects?:?\s*([^.]+)/i);
|
|
259
|
+
|
|
260
|
+
if (expected) result.expected_behavior = expected[1].trim();
|
|
261
|
+
if (actual) result.actual_behavior = actual[1].trim();
|
|
262
|
+
if (affects) {
|
|
263
|
+
result.affected_components = affects[1].split(/[,\s]+/).filter(c => c.includes('/') || c.includes('.'));
|
|
449
264
|
}
|
|
265
|
+
|
|
266
|
+
return result;
|
|
450
267
|
}
|
|
451
|
-
```
|
|
452
268
|
|
|
453
|
-
|
|
269
|
+
function parseMarkdownBody(body) {
|
|
270
|
+
if (!body) return {};
|
|
271
|
+
const result = {};
|
|
454
272
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
const
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
context: issueData.problem_statement,
|
|
466
|
-
source: issueData.source,
|
|
467
|
-
source_url: issueData.source_url || null,
|
|
468
|
-
labels: [...(issueData.labels || []), ...labels],
|
|
469
|
-
|
|
470
|
-
// Structured fields
|
|
471
|
-
problem_statement: issueData.problem_statement,
|
|
472
|
-
expected_behavior: issueData.expected_behavior || null,
|
|
473
|
-
actual_behavior: issueData.actual_behavior || null,
|
|
474
|
-
affected_components: issueData.affected_components || [],
|
|
475
|
-
reproduction_steps: issueData.reproduction_steps || [],
|
|
476
|
-
|
|
477
|
-
// Extended context (universal)
|
|
478
|
-
extended_context: issueData.extended_context || null,
|
|
479
|
-
|
|
480
|
-
// Closed-loop lifecycle requirements
|
|
481
|
-
lifecycle_requirements: issueData.lifecycle_requirements || {
|
|
482
|
-
test_strategy: 'auto',
|
|
483
|
-
regression_scope: 'affected',
|
|
484
|
-
acceptance_type: 'automated',
|
|
485
|
-
commit_strategy: 'per-task'
|
|
486
|
-
},
|
|
487
|
-
|
|
488
|
-
// Metadata
|
|
489
|
-
bound_solution_id: null,
|
|
490
|
-
solution_count: 0,
|
|
491
|
-
created_at: new Date().toISOString(),
|
|
492
|
-
updated_at: new Date().toISOString()
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
// Ensure directory exists
|
|
496
|
-
Bash('mkdir -p .workflow/issues');
|
|
497
|
-
|
|
498
|
-
// Append to issues.jsonl with proper newline handling
|
|
499
|
-
const issuesPath = '.workflow/issues/issues.jsonl';
|
|
500
|
-
const jsonLine = JSON.stringify(newIssue);
|
|
501
|
-
// Ensure file ends with newline before appending, then append with trailing newline
|
|
502
|
-
Bash(`[ -s "${issuesPath}" ] && [ -n "$(tail -c 1 "${issuesPath}")" ] && printf '\\n' >> "${issuesPath}"; printf '%s\\n' '${jsonLine}' >> "${issuesPath}"`);
|
|
503
|
-
|
|
504
|
-
console.log(`
|
|
505
|
-
## Issue Created
|
|
506
|
-
|
|
507
|
-
**ID**: ${newIssue.id}
|
|
508
|
-
**Title**: ${newIssue.title}
|
|
509
|
-
**Priority**: ${newIssue.priority}
|
|
510
|
-
**Labels**: ${newIssue.labels.join(', ') || 'none'}
|
|
511
|
-
**Source**: ${newIssue.source}
|
|
512
|
-
|
|
513
|
-
### Next Steps
|
|
514
|
-
1. Plan solution: \`/issue:plan ${newIssue.id}\`
|
|
515
|
-
2. View details: \`ccw issue status ${newIssue.id}\`
|
|
516
|
-
3. Manage issues: \`/issue:manage\`
|
|
517
|
-
`);
|
|
273
|
+
const problem = body.match(/##?\s*(problem|description)[:\s]*([\s\S]*?)(?=##|$)/i);
|
|
274
|
+
const expected = body.match(/##?\s*expected[:\s]*([\s\S]*?)(?=##|$)/i);
|
|
275
|
+
const actual = body.match(/##?\s*actual[:\s]*([\s\S]*?)(?=##|$)/i);
|
|
276
|
+
|
|
277
|
+
if (problem) result.context = problem[2].trim().substring(0, 500);
|
|
278
|
+
if (expected) result.expected_behavior = expected[2].trim();
|
|
279
|
+
if (actual) result.actual_behavior = actual[2].trim();
|
|
280
|
+
|
|
281
|
+
return result;
|
|
282
|
+
}
|
|
518
283
|
```
|
|
519
284
|
|
|
520
285
|
## Examples
|
|
521
286
|
|
|
522
|
-
###
|
|
287
|
+
### Clear Input (No Questions)
|
|
523
288
|
|
|
524
289
|
```bash
|
|
525
|
-
/issue:new https://github.com/
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
**Title**: Fix memory leak in WebSocket handler
|
|
531
|
-
**Priority**: 2
|
|
532
|
-
**Labels**: bug, performance
|
|
533
|
-
**Source**: github (https://github.com/myorg/myrepo/issues/42)
|
|
290
|
+
/issue:new https://github.com/org/repo/issues/42
|
|
291
|
+
# → Fetches, parses, creates immediately
|
|
292
|
+
|
|
293
|
+
/issue:new "Login fails with special chars. Expected: success. Actual: 500"
|
|
294
|
+
# → Parses structure, creates immediately
|
|
534
295
|
```
|
|
535
296
|
|
|
536
|
-
###
|
|
297
|
+
### Vague Input (1 Question)
|
|
537
298
|
|
|
538
299
|
```bash
|
|
539
|
-
/issue:new "
|
|
540
|
-
|
|
541
|
-
#
|
|
542
|
-
|
|
543
|
-
**ID**: ISS-20251227-142530
|
|
544
|
-
**Title**: API rate limiting not working
|
|
545
|
-
**Priority**: 3
|
|
546
|
-
**Labels**: none
|
|
547
|
-
**Source**: text
|
|
300
|
+
/issue:new "auth broken"
|
|
301
|
+
# → Asks: "Input unclear. What is the issue about?"
|
|
302
|
+
# → User provides details → saved to feedback[]
|
|
303
|
+
# → Creates issue
|
|
548
304
|
```
|
|
549
305
|
|
|
550
|
-
## Error Handling
|
|
551
|
-
|
|
552
|
-
| Error | Resolution |
|
|
553
|
-
|-------|------------|
|
|
554
|
-
| Invalid GitHub URL | Show format hint, ask for correction |
|
|
555
|
-
| gh CLI not available | Fall back to WebFetch for public issues |
|
|
556
|
-
| Empty description | Prompt user for required fields |
|
|
557
|
-
| Duplicate issue ID | Auto-increment or suggest merge |
|
|
558
|
-
| Parse failure | Show raw input, ask for manual structuring |
|
|
559
|
-
|
|
560
306
|
## Related Commands
|
|
561
307
|
|
|
562
308
|
- `/issue:plan` - Plan solution for issue
|
|
563
309
|
- `/issue:manage` - Interactive issue management
|
|
564
|
-
- `ccw issue list` - List all issues
|
|
565
|
-
- `ccw issue status <id>` - View issue details
|