claude-cli-advanced-starter-pack 1.0.0
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/LICENSE +21 -0
- package/OVERVIEW.md +597 -0
- package/README.md +439 -0
- package/bin/gtask.js +282 -0
- package/bin/postinstall.js +53 -0
- package/package.json +69 -0
- package/src/agents/phase-dev-templates.js +1011 -0
- package/src/agents/templates.js +668 -0
- package/src/analysis/checklist-parser.js +414 -0
- package/src/analysis/codebase.js +481 -0
- package/src/cli/menu.js +958 -0
- package/src/commands/claude-audit.js +1482 -0
- package/src/commands/claude-settings.js +2243 -0
- package/src/commands/create-agent.js +681 -0
- package/src/commands/create-command.js +337 -0
- package/src/commands/create-hook.js +262 -0
- package/src/commands/create-phase-dev/codebase-analyzer.js +813 -0
- package/src/commands/create-phase-dev/documentation-generator.js +352 -0
- package/src/commands/create-phase-dev/post-completion.js +404 -0
- package/src/commands/create-phase-dev/scale-calculator.js +344 -0
- package/src/commands/create-phase-dev/wizard.js +492 -0
- package/src/commands/create-phase-dev.js +481 -0
- package/src/commands/create-skill.js +313 -0
- package/src/commands/create.js +446 -0
- package/src/commands/decompose.js +392 -0
- package/src/commands/detect-tech-stack.js +768 -0
- package/src/commands/explore-mcp/claude-md-updater.js +252 -0
- package/src/commands/explore-mcp/mcp-installer.js +346 -0
- package/src/commands/explore-mcp/mcp-registry.js +438 -0
- package/src/commands/explore-mcp.js +638 -0
- package/src/commands/gtask-init.js +641 -0
- package/src/commands/help.js +128 -0
- package/src/commands/init.js +1890 -0
- package/src/commands/install.js +250 -0
- package/src/commands/list.js +116 -0
- package/src/commands/roadmap.js +750 -0
- package/src/commands/setup-wizard.js +482 -0
- package/src/commands/setup.js +351 -0
- package/src/commands/sync.js +534 -0
- package/src/commands/test-run.js +456 -0
- package/src/commands/test-setup.js +456 -0
- package/src/commands/validate.js +67 -0
- package/src/config/tech-stack.defaults.json +182 -0
- package/src/config/tech-stack.schema.json +502 -0
- package/src/github/client.js +359 -0
- package/src/index.js +84 -0
- package/src/templates/claude-command.js +244 -0
- package/src/templates/issue-body.js +284 -0
- package/src/testing/config.js +411 -0
- package/src/utils/template-engine.js +398 -0
- package/src/utils/validate-templates.js +223 -0
- package/src/utils.js +396 -0
- package/templates/commands/ccasp-setup.template.md +113 -0
- package/templates/commands/context-audit.template.md +97 -0
- package/templates/commands/create-task-list.template.md +382 -0
- package/templates/commands/deploy-full.template.md +261 -0
- package/templates/commands/github-task-start.template.md +99 -0
- package/templates/commands/github-update.template.md +69 -0
- package/templates/commands/happy-start.template.md +117 -0
- package/templates/commands/phase-track.template.md +142 -0
- package/templates/commands/tunnel-start.template.md +127 -0
- package/templates/commands/tunnel-stop.template.md +106 -0
- package/templates/hooks/context-guardian.template.js +173 -0
- package/templates/hooks/deployment-orchestrator.template.js +219 -0
- package/templates/hooks/github-progress-hook.template.js +197 -0
- package/templates/hooks/happy-checkpoint-manager.template.js +222 -0
- package/templates/hooks/phase-dev-enforcer.template.js +183 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create Task Command
|
|
3
|
+
*
|
|
4
|
+
* Interactive task creation with codebase analysis
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import inquirer from 'inquirer';
|
|
9
|
+
import ora from 'ora';
|
|
10
|
+
import { showHeader, showSuccess, showError, showWarning, showInfo } from '../cli/menu.js';
|
|
11
|
+
import { loadConfigSync } from '../utils.js';
|
|
12
|
+
import { createIssue, addIssueToProject, getProjectItemId, updateProjectItemField } from '../github/client.js';
|
|
13
|
+
import { analyzeForIssue, detectProjectType } from '../analysis/codebase.js';
|
|
14
|
+
import { generateIssueBody, generateSimpleIssueBody, suggestAcceptanceCriteria } from '../templates/issue-body.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Label categories
|
|
18
|
+
*/
|
|
19
|
+
const LABEL_CATEGORIES = {
|
|
20
|
+
type: [
|
|
21
|
+
{ name: 'bug', description: 'Something isn\'t working' },
|
|
22
|
+
{ name: 'feature', description: 'New functionality' },
|
|
23
|
+
{ name: 'feature-update', description: 'Enhancement to existing feature' },
|
|
24
|
+
{ name: 'refactor', description: 'Code improvement without behavior change' },
|
|
25
|
+
{ name: 'documentation', description: 'Documentation only' },
|
|
26
|
+
],
|
|
27
|
+
stack: [
|
|
28
|
+
{ name: 'frontend', description: 'UI/client changes' },
|
|
29
|
+
{ name: 'backend', description: 'API/server changes' },
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Priority options
|
|
35
|
+
*/
|
|
36
|
+
const PRIORITIES = [
|
|
37
|
+
{ name: 'P0-Critical', description: 'Production broken, blocks all users' },
|
|
38
|
+
{ name: 'P1-High', description: 'Major feature broken, affects many users' },
|
|
39
|
+
{ name: 'P2-Medium', description: 'Minor bug or new feature (default)' },
|
|
40
|
+
{ name: 'P3-Low', description: 'Nice to have, polish, cleanup' },
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Run the create command
|
|
45
|
+
*/
|
|
46
|
+
export async function runCreate(options) {
|
|
47
|
+
showHeader('Create GitHub Task');
|
|
48
|
+
|
|
49
|
+
// Load config
|
|
50
|
+
const { config, path: configPath } = loadConfigSync();
|
|
51
|
+
|
|
52
|
+
if (!config || !config.project_board?.owner) {
|
|
53
|
+
showError('Not configured', 'Run "gtask setup" first to configure your project.');
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const { owner, repo, project_number: projectNumber, project_id: projectId } = config.project_board;
|
|
58
|
+
|
|
59
|
+
console.log(chalk.dim(`Creating task for ${owner}/${repo}`));
|
|
60
|
+
if (projectNumber) {
|
|
61
|
+
console.log(chalk.dim(`Project board: #${projectNumber}`));
|
|
62
|
+
}
|
|
63
|
+
console.log('');
|
|
64
|
+
|
|
65
|
+
// Gather task details
|
|
66
|
+
const taskData = await gatherTaskDetails(options, config);
|
|
67
|
+
|
|
68
|
+
if (!taskData) {
|
|
69
|
+
return; // User cancelled
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Perform codebase analysis
|
|
73
|
+
let codeAnalysis = null;
|
|
74
|
+
if (!options.skipAnalysis) {
|
|
75
|
+
const analyzeSpinner = ora('Analyzing codebase...').start();
|
|
76
|
+
try {
|
|
77
|
+
// Extract keywords from title and description
|
|
78
|
+
const keywords = extractKeywords(taskData.title, taskData.description);
|
|
79
|
+
codeAnalysis = await analyzeForIssue(keywords, { maxFiles: 5 });
|
|
80
|
+
analyzeSpinner.succeed(`Found ${codeAnalysis.relevantFiles.length} relevant files`);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
analyzeSpinner.warn('Codebase analysis skipped');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Generate issue body
|
|
87
|
+
const spinner = ora('Generating issue body...').start();
|
|
88
|
+
|
|
89
|
+
const issueBody = codeAnalysis
|
|
90
|
+
? generateIssueBody({
|
|
91
|
+
description: taskData.description,
|
|
92
|
+
expectedBehavior: taskData.expectedBehavior,
|
|
93
|
+
actualBehavior: taskData.actualBehavior,
|
|
94
|
+
acceptanceCriteria: taskData.acceptanceCriteria,
|
|
95
|
+
codeAnalysis,
|
|
96
|
+
todoList: generateTodoList(taskData, codeAnalysis),
|
|
97
|
+
testScenarios: generateTestScenarios(taskData),
|
|
98
|
+
priority: taskData.priority,
|
|
99
|
+
labels: taskData.labels,
|
|
100
|
+
})
|
|
101
|
+
: generateSimpleIssueBody({
|
|
102
|
+
description: taskData.description,
|
|
103
|
+
acceptanceCriteria: taskData.acceptanceCriteria,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
spinner.succeed('Issue body generated');
|
|
107
|
+
|
|
108
|
+
// Preview
|
|
109
|
+
console.log('');
|
|
110
|
+
console.log(chalk.cyan('─'.repeat(60)));
|
|
111
|
+
console.log(chalk.bold('Preview:'));
|
|
112
|
+
console.log(chalk.cyan('─'.repeat(60)));
|
|
113
|
+
console.log(chalk.dim(issueBody.slice(0, 500) + '...'));
|
|
114
|
+
console.log(chalk.cyan('─'.repeat(60)));
|
|
115
|
+
console.log('');
|
|
116
|
+
|
|
117
|
+
// Confirm creation
|
|
118
|
+
const { confirmCreate } = await inquirer.prompt([
|
|
119
|
+
{
|
|
120
|
+
type: 'confirm',
|
|
121
|
+
name: 'confirmCreate',
|
|
122
|
+
message: 'Create this issue?',
|
|
123
|
+
default: true,
|
|
124
|
+
},
|
|
125
|
+
]);
|
|
126
|
+
|
|
127
|
+
if (!confirmCreate) {
|
|
128
|
+
console.log(chalk.yellow('Cancelled.'));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Create the issue
|
|
133
|
+
const createSpinner = ora('Creating GitHub issue...').start();
|
|
134
|
+
|
|
135
|
+
const result = await createIssue(owner, repo, {
|
|
136
|
+
title: taskData.title,
|
|
137
|
+
body: issueBody,
|
|
138
|
+
labels: taskData.labels,
|
|
139
|
+
assignees: [owner],
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
if (!result.success) {
|
|
143
|
+
createSpinner.fail('Failed to create issue');
|
|
144
|
+
showError('Error', result.error);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
createSpinner.succeed(`Issue #${result.number} created`);
|
|
149
|
+
|
|
150
|
+
// Add to project board
|
|
151
|
+
if (projectNumber) {
|
|
152
|
+
const projectSpinner = ora('Adding to project board...').start();
|
|
153
|
+
const added = addIssueToProject(owner, projectNumber, result.url);
|
|
154
|
+
|
|
155
|
+
if (added) {
|
|
156
|
+
projectSpinner.succeed('Added to project board');
|
|
157
|
+
|
|
158
|
+
// Update fields if we have IDs
|
|
159
|
+
if (projectId && config.field_ids?.status) {
|
|
160
|
+
const itemId = getProjectItemId(owner, projectNumber, result.number);
|
|
161
|
+
|
|
162
|
+
if (itemId) {
|
|
163
|
+
// Set status to "Todo"
|
|
164
|
+
if (config.status_options?.todo) {
|
|
165
|
+
updateProjectItemField(
|
|
166
|
+
projectId,
|
|
167
|
+
itemId,
|
|
168
|
+
config.field_ids.status,
|
|
169
|
+
config.status_options.todo,
|
|
170
|
+
'single-select'
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Set priority if available
|
|
175
|
+
if (config.field_ids?.priority && config.priority_options) {
|
|
176
|
+
const priorityKey = taskData.priority.toLowerCase().replace('-', '').slice(0, 2);
|
|
177
|
+
const priorityOptionId = config.priority_options[priorityKey];
|
|
178
|
+
if (priorityOptionId) {
|
|
179
|
+
updateProjectItemField(
|
|
180
|
+
projectId,
|
|
181
|
+
itemId,
|
|
182
|
+
config.field_ids.priority,
|
|
183
|
+
priorityOptionId,
|
|
184
|
+
'single-select'
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
projectSpinner.warn('Could not add to project board');
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Success summary
|
|
196
|
+
showSuccess('Task Created Successfully', [
|
|
197
|
+
`Issue: #${result.number} - ${taskData.title}`,
|
|
198
|
+
`URL: ${result.url}`,
|
|
199
|
+
`Priority: ${taskData.priority}`,
|
|
200
|
+
`Labels: ${taskData.labels.join(', ')}`,
|
|
201
|
+
'',
|
|
202
|
+
'Next: Start working or create another task',
|
|
203
|
+
]);
|
|
204
|
+
|
|
205
|
+
return result;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Gather task details interactively
|
|
210
|
+
*/
|
|
211
|
+
async function gatherTaskDetails(options, config) {
|
|
212
|
+
const data = {
|
|
213
|
+
title: options.title || '',
|
|
214
|
+
description: options.description || '',
|
|
215
|
+
priority: options.priority || 'P2-Medium',
|
|
216
|
+
labels: options.labels ? options.labels.split(',').map((l) => l.trim()) : [],
|
|
217
|
+
acceptanceCriteria: [],
|
|
218
|
+
expectedBehavior: '',
|
|
219
|
+
actualBehavior: '',
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Batch mode - parse from options
|
|
223
|
+
if (options.batch) {
|
|
224
|
+
if (!data.title || !data.description) {
|
|
225
|
+
showError('Batch mode requires --title and --description');
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
return data;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Interactive mode
|
|
232
|
+
|
|
233
|
+
// Title
|
|
234
|
+
if (!data.title) {
|
|
235
|
+
const { title } = await inquirer.prompt([
|
|
236
|
+
{
|
|
237
|
+
type: 'input',
|
|
238
|
+
name: 'title',
|
|
239
|
+
message: 'Issue title:',
|
|
240
|
+
validate: (input) => (input.trim() ? true : 'Title is required'),
|
|
241
|
+
},
|
|
242
|
+
]);
|
|
243
|
+
data.title = title.trim();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Type (determines other fields)
|
|
247
|
+
const { issueType } = await inquirer.prompt([
|
|
248
|
+
{
|
|
249
|
+
type: 'list',
|
|
250
|
+
name: 'issueType',
|
|
251
|
+
message: 'Issue type:',
|
|
252
|
+
choices: LABEL_CATEGORIES.type.map((t) => ({
|
|
253
|
+
name: `${t.name} - ${chalk.dim(t.description)}`,
|
|
254
|
+
value: t.name,
|
|
255
|
+
})),
|
|
256
|
+
},
|
|
257
|
+
]);
|
|
258
|
+
data.labels.push(issueType);
|
|
259
|
+
|
|
260
|
+
// Description
|
|
261
|
+
console.log('');
|
|
262
|
+
console.log(chalk.dim('Enter description (press Enter twice to finish):'));
|
|
263
|
+
const { description } = await inquirer.prompt([
|
|
264
|
+
{
|
|
265
|
+
type: 'editor',
|
|
266
|
+
name: 'description',
|
|
267
|
+
message: 'Description:',
|
|
268
|
+
default: data.description || '',
|
|
269
|
+
},
|
|
270
|
+
]);
|
|
271
|
+
data.description = description.trim();
|
|
272
|
+
|
|
273
|
+
// Bug-specific fields
|
|
274
|
+
if (issueType === 'bug') {
|
|
275
|
+
const { expectedBehavior, actualBehavior } = await inquirer.prompt([
|
|
276
|
+
{
|
|
277
|
+
type: 'input',
|
|
278
|
+
name: 'expectedBehavior',
|
|
279
|
+
message: 'Expected behavior:',
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
type: 'input',
|
|
283
|
+
name: 'actualBehavior',
|
|
284
|
+
message: 'Actual behavior:',
|
|
285
|
+
},
|
|
286
|
+
]);
|
|
287
|
+
data.expectedBehavior = expectedBehavior;
|
|
288
|
+
data.actualBehavior = actualBehavior;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Stack
|
|
292
|
+
const { stack } = await inquirer.prompt([
|
|
293
|
+
{
|
|
294
|
+
type: 'checkbox',
|
|
295
|
+
name: 'stack',
|
|
296
|
+
message: 'Stack affected:',
|
|
297
|
+
choices: LABEL_CATEGORIES.stack.map((s) => ({
|
|
298
|
+
name: `${s.name} - ${chalk.dim(s.description)}`,
|
|
299
|
+
value: s.name,
|
|
300
|
+
})),
|
|
301
|
+
validate: (input) =>
|
|
302
|
+
input.length > 0 ? true : 'Select at least one stack',
|
|
303
|
+
},
|
|
304
|
+
]);
|
|
305
|
+
data.labels.push(...stack);
|
|
306
|
+
|
|
307
|
+
// Priority
|
|
308
|
+
const { priority } = await inquirer.prompt([
|
|
309
|
+
{
|
|
310
|
+
type: 'list',
|
|
311
|
+
name: 'priority',
|
|
312
|
+
message: 'Priority:',
|
|
313
|
+
choices: PRIORITIES.map((p) => ({
|
|
314
|
+
name: `${p.name} - ${chalk.dim(p.description)}`,
|
|
315
|
+
value: p.name,
|
|
316
|
+
})),
|
|
317
|
+
default: 2, // P2-Medium
|
|
318
|
+
},
|
|
319
|
+
]);
|
|
320
|
+
data.priority = priority;
|
|
321
|
+
|
|
322
|
+
// Acceptance criteria
|
|
323
|
+
const suggestedCriteria = suggestAcceptanceCriteria(issueType);
|
|
324
|
+
console.log('');
|
|
325
|
+
console.log(chalk.dim('Suggested acceptance criteria:'));
|
|
326
|
+
suggestedCriteria.forEach((c, i) => console.log(chalk.dim(` ${i + 1}. ${c}`)));
|
|
327
|
+
|
|
328
|
+
const { useSuggested } = await inquirer.prompt([
|
|
329
|
+
{
|
|
330
|
+
type: 'confirm',
|
|
331
|
+
name: 'useSuggested',
|
|
332
|
+
message: 'Use suggested acceptance criteria?',
|
|
333
|
+
default: true,
|
|
334
|
+
},
|
|
335
|
+
]);
|
|
336
|
+
|
|
337
|
+
if (useSuggested) {
|
|
338
|
+
data.acceptanceCriteria = [...suggestedCriteria];
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const { additionalCriteria } = await inquirer.prompt([
|
|
342
|
+
{
|
|
343
|
+
type: 'input',
|
|
344
|
+
name: 'additionalCriteria',
|
|
345
|
+
message: 'Additional acceptance criteria (comma-separated, or Enter to skip):',
|
|
346
|
+
},
|
|
347
|
+
]);
|
|
348
|
+
|
|
349
|
+
if (additionalCriteria.trim()) {
|
|
350
|
+
const additional = additionalCriteria.split(',').map((c) => c.trim()).filter(Boolean);
|
|
351
|
+
data.acceptanceCriteria.push(...additional);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return data;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Extract keywords from title and description for codebase search
|
|
359
|
+
*/
|
|
360
|
+
function extractKeywords(title, description) {
|
|
361
|
+
const text = `${title} ${description}`.toLowerCase();
|
|
362
|
+
|
|
363
|
+
// Remove common words
|
|
364
|
+
const stopWords = new Set([
|
|
365
|
+
'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
|
|
366
|
+
'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could',
|
|
367
|
+
'should', 'may', 'might', 'must', 'shall', 'can', 'need', 'to', 'of',
|
|
368
|
+
'in', 'for', 'on', 'with', 'at', 'by', 'from', 'as', 'into', 'through',
|
|
369
|
+
'during', 'before', 'after', 'above', 'below', 'between', 'under',
|
|
370
|
+
'again', 'further', 'then', 'once', 'here', 'there', 'when', 'where',
|
|
371
|
+
'why', 'how', 'all', 'each', 'few', 'more', 'most', 'other', 'some',
|
|
372
|
+
'such', 'no', 'nor', 'not', 'only', 'own', 'same', 'so', 'than', 'too',
|
|
373
|
+
'very', 'just', 'and', 'but', 'if', 'or', 'because', 'until', 'while',
|
|
374
|
+
'although', 'though', 'this', 'that', 'these', 'those', 'i', 'you', 'he',
|
|
375
|
+
'she', 'it', 'we', 'they', 'what', 'which', 'who', 'whom', 'bug', 'fix',
|
|
376
|
+
'issue', 'problem', 'error', 'broken', 'working', 'work', 'doesnt', 'dont',
|
|
377
|
+
]);
|
|
378
|
+
|
|
379
|
+
// Extract words
|
|
380
|
+
const words = text
|
|
381
|
+
.replace(/[^a-z0-9\s]/g, ' ')
|
|
382
|
+
.split(/\s+/)
|
|
383
|
+
.filter((w) => w.length > 2 && !stopWords.has(w));
|
|
384
|
+
|
|
385
|
+
// Dedupe and limit
|
|
386
|
+
const unique = [...new Set(words)];
|
|
387
|
+
return unique.slice(0, 10);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Generate todo list from task data and analysis
|
|
392
|
+
*/
|
|
393
|
+
function generateTodoList(taskData, codeAnalysis) {
|
|
394
|
+
const todos = [];
|
|
395
|
+
|
|
396
|
+
// Add steps based on relevant files found
|
|
397
|
+
if (codeAnalysis?.relevantFiles?.length > 0) {
|
|
398
|
+
for (const fileInfo of codeAnalysis.relevantFiles.slice(0, 3)) {
|
|
399
|
+
if (fileInfo.definitions?.length > 0) {
|
|
400
|
+
const mainDef = fileInfo.definitions[0];
|
|
401
|
+
todos.push({
|
|
402
|
+
task: `Review and update ${mainDef.name}() in ${fileInfo.file}`,
|
|
403
|
+
file: fileInfo.file,
|
|
404
|
+
details: `Line ${mainDef.line}`,
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Add testing step
|
|
411
|
+
todos.push({
|
|
412
|
+
task: 'Test changes locally',
|
|
413
|
+
details: 'Verify fix works in development environment',
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
// Add PR step
|
|
417
|
+
todos.push({
|
|
418
|
+
task: 'Create commit with descriptive message',
|
|
419
|
+
details: `Reference issue number in commit: "fix: description (#${taskData.issueNumber || 'N'})"`,
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
return todos;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Generate test scenarios
|
|
427
|
+
*/
|
|
428
|
+
function generateTestScenarios(taskData) {
|
|
429
|
+
const scenarios = [];
|
|
430
|
+
|
|
431
|
+
// Basic happy path
|
|
432
|
+
scenarios.push({
|
|
433
|
+
name: 'Happy path - normal usage',
|
|
434
|
+
steps: ['Navigate to feature', 'Perform action', 'Verify result'],
|
|
435
|
+
expected: 'Feature works as expected',
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
// Edge case
|
|
439
|
+
scenarios.push({
|
|
440
|
+
name: 'Edge case - boundary conditions',
|
|
441
|
+
steps: ['Test with edge case input', 'Verify handling'],
|
|
442
|
+
expected: 'No errors, graceful handling',
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
return scenarios;
|
|
446
|
+
}
|