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.
Files changed (70) hide show
  1. package/.claude/agents/issue-plan-agent.md +57 -103
  2. package/.claude/agents/issue-queue-agent.md +69 -120
  3. package/.claude/commands/issue/new.md +217 -473
  4. package/.claude/commands/issue/plan.md +76 -154
  5. package/.claude/commands/issue/queue.md +208 -259
  6. package/.claude/skills/issue-manage/SKILL.md +63 -22
  7. package/.claude/workflows/cli-templates/schemas/discovery-finding-schema.json +3 -3
  8. package/.claude/workflows/cli-templates/schemas/issues-jsonl-schema.json +3 -3
  9. package/.claude/workflows/cli-templates/schemas/queue-schema.json +0 -5
  10. package/.codex/prompts/issue-plan.md +16 -19
  11. package/.codex/prompts/issue-queue.md +0 -1
  12. package/README.md +1 -0
  13. package/ccw/dist/cli.d.ts.map +1 -1
  14. package/ccw/dist/cli.js +4 -1
  15. package/ccw/dist/cli.js.map +1 -1
  16. package/ccw/dist/commands/cli.d.ts +1 -0
  17. package/ccw/dist/commands/cli.d.ts.map +1 -1
  18. package/ccw/dist/commands/cli.js +59 -6
  19. package/ccw/dist/commands/cli.js.map +1 -1
  20. package/ccw/dist/commands/issue.d.ts +3 -1
  21. package/ccw/dist/commands/issue.d.ts.map +1 -1
  22. package/ccw/dist/commands/issue.js +383 -30
  23. package/ccw/dist/commands/issue.js.map +1 -1
  24. package/ccw/dist/core/routes/issue-routes.d.ts.map +1 -1
  25. package/ccw/dist/core/routes/issue-routes.js +77 -16
  26. package/ccw/dist/core/routes/issue-routes.js.map +1 -1
  27. package/ccw/dist/tools/cli-executor.d.ts.map +1 -1
  28. package/ccw/dist/tools/cli-executor.js +119 -4
  29. package/ccw/dist/tools/cli-executor.js.map +1 -1
  30. package/ccw/dist/tools/litellm-executor.d.ts +4 -0
  31. package/ccw/dist/tools/litellm-executor.d.ts.map +1 -1
  32. package/ccw/dist/tools/litellm-executor.js +54 -1
  33. package/ccw/dist/tools/litellm-executor.js.map +1 -1
  34. package/ccw/dist/tools/ui-generate-preview.d.ts +18 -0
  35. package/ccw/dist/tools/ui-generate-preview.d.ts.map +1 -1
  36. package/ccw/dist/tools/ui-generate-preview.js +26 -10
  37. package/ccw/dist/tools/ui-generate-preview.js.map +1 -1
  38. package/ccw/src/cli.ts +4 -1
  39. package/ccw/src/commands/cli.ts +64 -6
  40. package/ccw/src/commands/issue.ts +442 -34
  41. package/ccw/src/core/routes/issue-routes.ts +82 -16
  42. package/ccw/src/tools/cli-executor.ts +127 -4
  43. package/ccw/src/tools/litellm-executor.ts +107 -24
  44. package/ccw/src/tools/ui-generate-preview.js +60 -37
  45. package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
  46. package/codex-lens/src/codexlens/__pycache__/entities.cpython-313.pyc +0 -0
  47. package/codex-lens/src/codexlens/config.py +25 -2
  48. package/codex-lens/src/codexlens/entities.py +5 -1
  49. package/codex-lens/src/codexlens/indexing/__pycache__/symbol_extractor.cpython-313.pyc +0 -0
  50. package/codex-lens/src/codexlens/indexing/symbol_extractor.py +243 -243
  51. package/codex-lens/src/codexlens/parsers/__pycache__/factory.cpython-313.pyc +0 -0
  52. package/codex-lens/src/codexlens/parsers/__pycache__/treesitter_parser.cpython-313.pyc +0 -0
  53. package/codex-lens/src/codexlens/parsers/factory.py +256 -256
  54. package/codex-lens/src/codexlens/parsers/treesitter_parser.py +335 -335
  55. package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
  56. package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
  57. package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
  58. package/codex-lens/src/codexlens/search/chain_search.py +30 -1
  59. package/codex-lens/src/codexlens/semantic/__pycache__/__init__.cpython-313.pyc +0 -0
  60. package/codex-lens/src/codexlens/semantic/__pycache__/embedder.cpython-313.pyc +0 -0
  61. package/codex-lens/src/codexlens/semantic/__pycache__/reranker.cpython-313.pyc +0 -0
  62. package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
  63. package/codex-lens/src/codexlens/semantic/embedder.py +6 -9
  64. package/codex-lens/src/codexlens/semantic/vector_store.py +271 -200
  65. package/codex-lens/src/codexlens/storage/__pycache__/dir_index.cpython-313.pyc +0 -0
  66. package/codex-lens/src/codexlens/storage/__pycache__/index_tree.cpython-313.pyc +0 -0
  67. package/codex-lens/src/codexlens/storage/__pycache__/sqlite_store.cpython-313.pyc +0 -0
  68. package/codex-lens/src/codexlens/storage/sqlite_store.py +184 -108
  69. package/package.json +6 -1
  70. 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, extracting key elements into issues.jsonl
4
- argument-hint: "<github-url | text-description> [--priority 1-5] [--labels label1,label2]"
5
- allowed-tools: TodoWrite(*), Bash(*), Read(*), Write(*), WebFetch(*), AskUserQuestion(*)
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
- ## Overview
10
+ ## Core Principle
11
11
 
12
- Creates a new structured issue from either:
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
- Outputs a well-formed issue entry to `.workflow/issues/issues.jsonl`.
14
+ ```
15
+ Clear Input (GitHub URL, structured text) → Direct creation
16
+ Unclear Input (vague description) → Minimal clarifying questions
17
+ ```
17
18
 
18
- ## Issue Structure (Closed-Loop)
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; // Issue title (clear, concise)
24
- status: 'registered'; // Initial status
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'; // Input source type
28
- source_url?: string; // GitHub URL if applicable
29
- labels?: string[]; // Categorization labels
30
-
31
- // Structured extraction
32
- problem_statement: string; // What is the problem?
33
- expected_behavior?: string; // What should happen?
34
- actual_behavior?: string; // What actually happens?
35
- affected_components?: string[];// Files/modules affected
36
- reproduction_steps?: string[]; // Steps to reproduce
37
-
38
- // Extended context (minimal, for planning hints)
39
- extended_context?: {
40
- location?: string; // file:line when specific line matters
41
- suggested_fix?: string; // Suggested remediation
42
- notes?: string; // Additional notes (user clarifications or discovery hints)
43
- };
44
-
45
- // Closed-loop requirements (guide plan generation)
46
- lifecycle_requirements: {
47
- test_strategy: 'unit' | 'integration' | 'e2e' | 'manual' | 'auto';
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
- ## Lifecycle Requirements
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
- # From GitHub URL
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
- # From text description
81
- /issue:new "Login fails when password contains special characters. Expected: successful login. Actual: 500 error. Affects src/auth/*"
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, --labels
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+)$/); // #123 format
75
+ const isGitHubShort = input.match(/^#(\d+)$/);
76
+ const hasStructure = input.match(/(expected|actual|affects|steps):/i);
98
77
 
99
- let issueData = {};
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
- if (isGitHubUrl || isGitHubShort) {
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 Issue Fetching
88
+ ### Phase 2: Data Extraction (GitHub or Text)
111
89
 
112
90
  ```javascript
113
- async function fetchGitHubIssue(urlOrNumber) {
114
- let issueRef;
115
-
116
- if (urlOrNumber.startsWith('http')) {
117
- // Extract owner/repo/number from URL
118
- const match = urlOrNumber.match(/github\.com\/([\w-]+)\/([\w-]+)\/issues\/(\d+)/);
119
- if (!match) throw new Error('Invalid GitHub URL');
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: ghIssue.url,
138
- labels: ghIssue.labels.map(l => l.name),
139
- context: ghIssue.body,
140
- ...parsed
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: Text Description Parsing
114
+ ### Phase 3: Lightweight Context Hint (Conditional)
186
115
 
187
116
  ```javascript
188
- async function parseTextDescription(text) {
189
- // Generate unique ID
190
- const id = `ISS-${new Date().toISOString().replace(/[-:T]/g, '').slice(0, 14)}`;
191
-
192
- // Extract structured elements using patterns
193
- const result = {
194
- id,
195
- source: 'text',
196
- title: '',
197
- problem_statement: '',
198
- expected_behavior: null,
199
- actual_behavior: null,
200
- affected_components: [],
201
- reproduction_steps: []
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: Lifecycle Configuration
138
+ ### Phase 4: Conditional Clarification (Only if Unclear)
238
139
 
239
140
  ```javascript
240
- // Ask for lifecycle requirements (or use smart defaults)
241
- const lifecycleAnswer = AskUserQuestion({
242
- questions: [
243
- {
244
- question: 'Test strategy for this issue?',
245
- header: 'Test',
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: 'per-task', description: 'One commit per task (Recommended)' },
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
- if (!issueData.actual_behavior && issueData.source !== 'discovery') {
304
- suggestions.push({
305
- field: 'actual_behavior',
306
- question: 'What is the actual behavior?',
307
- hint: 'Describe what currently happens (error message, wrong output, etc.)'
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
- if (!issueData.affected_components?.length) {
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
- if (!issueData.reproduction_steps?.length && issueData.source === 'text') {
320
- suggestions.push({
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
- // Ask follow-up questions if any suggestions exist
328
- let userNotes = '';
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
- The following information would help with issue resolution:
334
- ${suggestions.map((s, i) => `${i+1}. **${s.question}** - ${s.hint}`).join('\n')}
335
- `);
176
+ **Issue Creation** (via CLI endpoint):
177
+ ```bash
178
+ ccw issue create --data '{"title":"...", "context":"...", "priority":3, ...}'
179
+ ```
336
180
 
337
- const followUpAnswer = AskUserQuestion({
338
- questions: [{
339
- question: 'Would you like to provide additional details?',
340
- header: 'Clarify',
341
- multiSelect: false,
342
- options: [
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
- if (followUpAnswer.includes('Add details')) {
350
- // Collect additional notes via "Other" input
351
- const notesAnswer = AskUserQuestion({
352
- questions: [{
353
- question: 'Enter additional details (address any of the suggested questions):',
354
- header: 'Details',
355
- multiSelect: false,
356
- options: [
357
- { label: 'Use template', description: 'Expected: ... | Actual: ... | Files: ...' }
358
- ]
359
- }]
360
- });
361
-
362
- if (notesAnswer.customText) {
363
- userNotes = notesAnswer.customText;
364
-
365
- // Parse structured input if provided
366
- const expectedMatch = userNotes.match(/expected:\s*([^|]+)/i);
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
- // Store user notes in extended context
384
- issueData.extended_context = {
385
- ...(issueData.extended_context || {}),
386
- notes: userNotes || null
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
- ### Phase 5: User Confirmation
236
+ ## Helper Functions
391
237
 
392
238
  ```javascript
393
- // Show parsed data and ask for confirmation
394
- console.log(`
395
- ## Parsed Issue
396
-
397
- **ID**: ${issueData.id}
398
- **Title**: ${issueData.title}
399
- **Source**: ${issueData.source}${issueData.source_url ? ` (${issueData.source_url})` : ''}
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
- if (answer.includes('Edit Title')) {
436
- const titleAnswer = AskUserQuestion({
437
- questions: [{
438
- question: 'Enter new title:',
439
- header: 'Title',
440
- multiSelect: false,
441
- options: [
442
- { label: issueData.title.substring(0, 40), description: 'Keep current' }
443
- ]
444
- }]
445
- });
446
- // Handle custom input via "Other"
447
- if (titleAnswer.customText) {
448
- issueData.title = titleAnswer.customText;
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
- ### Phase 6: Write to JSONL
269
+ function parseMarkdownBody(body) {
270
+ if (!body) return {};
271
+ const result = {};
454
272
 
455
- ```javascript
456
- // Construct final issue object
457
- const priority = flags.priority ? parseInt(flags.priority) : 3;
458
- const labels = flags.labels ? flags.labels.split(',').map(l => l.trim()) : [];
459
-
460
- const newIssue = {
461
- id: issueData.id,
462
- title: issueData.title,
463
- status: 'registered',
464
- priority,
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
- ### GitHub Issue
287
+ ### Clear Input (No Questions)
523
288
 
524
289
  ```bash
525
- /issue:new https://github.com/myorg/myrepo/issues/42 --priority 2
526
-
527
- # Output:
528
- ## Issue Created
529
- **ID**: GH-42
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
- ### Text Description
297
+ ### Vague Input (1 Question)
537
298
 
538
299
  ```bash
539
- /issue:new "API rate limiting not working. Expected: 429 after 100 requests. Actual: No limit. Affects src/middleware/rate-limit.ts"
540
-
541
- # Output:
542
- ## Issue Created
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