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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/OVERVIEW.md +597 -0
  3. package/README.md +439 -0
  4. package/bin/gtask.js +282 -0
  5. package/bin/postinstall.js +53 -0
  6. package/package.json +69 -0
  7. package/src/agents/phase-dev-templates.js +1011 -0
  8. package/src/agents/templates.js +668 -0
  9. package/src/analysis/checklist-parser.js +414 -0
  10. package/src/analysis/codebase.js +481 -0
  11. package/src/cli/menu.js +958 -0
  12. package/src/commands/claude-audit.js +1482 -0
  13. package/src/commands/claude-settings.js +2243 -0
  14. package/src/commands/create-agent.js +681 -0
  15. package/src/commands/create-command.js +337 -0
  16. package/src/commands/create-hook.js +262 -0
  17. package/src/commands/create-phase-dev/codebase-analyzer.js +813 -0
  18. package/src/commands/create-phase-dev/documentation-generator.js +352 -0
  19. package/src/commands/create-phase-dev/post-completion.js +404 -0
  20. package/src/commands/create-phase-dev/scale-calculator.js +344 -0
  21. package/src/commands/create-phase-dev/wizard.js +492 -0
  22. package/src/commands/create-phase-dev.js +481 -0
  23. package/src/commands/create-skill.js +313 -0
  24. package/src/commands/create.js +446 -0
  25. package/src/commands/decompose.js +392 -0
  26. package/src/commands/detect-tech-stack.js +768 -0
  27. package/src/commands/explore-mcp/claude-md-updater.js +252 -0
  28. package/src/commands/explore-mcp/mcp-installer.js +346 -0
  29. package/src/commands/explore-mcp/mcp-registry.js +438 -0
  30. package/src/commands/explore-mcp.js +638 -0
  31. package/src/commands/gtask-init.js +641 -0
  32. package/src/commands/help.js +128 -0
  33. package/src/commands/init.js +1890 -0
  34. package/src/commands/install.js +250 -0
  35. package/src/commands/list.js +116 -0
  36. package/src/commands/roadmap.js +750 -0
  37. package/src/commands/setup-wizard.js +482 -0
  38. package/src/commands/setup.js +351 -0
  39. package/src/commands/sync.js +534 -0
  40. package/src/commands/test-run.js +456 -0
  41. package/src/commands/test-setup.js +456 -0
  42. package/src/commands/validate.js +67 -0
  43. package/src/config/tech-stack.defaults.json +182 -0
  44. package/src/config/tech-stack.schema.json +502 -0
  45. package/src/github/client.js +359 -0
  46. package/src/index.js +84 -0
  47. package/src/templates/claude-command.js +244 -0
  48. package/src/templates/issue-body.js +284 -0
  49. package/src/testing/config.js +411 -0
  50. package/src/utils/template-engine.js +398 -0
  51. package/src/utils/validate-templates.js +223 -0
  52. package/src/utils.js +396 -0
  53. package/templates/commands/ccasp-setup.template.md +113 -0
  54. package/templates/commands/context-audit.template.md +97 -0
  55. package/templates/commands/create-task-list.template.md +382 -0
  56. package/templates/commands/deploy-full.template.md +261 -0
  57. package/templates/commands/github-task-start.template.md +99 -0
  58. package/templates/commands/github-update.template.md +69 -0
  59. package/templates/commands/happy-start.template.md +117 -0
  60. package/templates/commands/phase-track.template.md +142 -0
  61. package/templates/commands/tunnel-start.template.md +127 -0
  62. package/templates/commands/tunnel-stop.template.md +106 -0
  63. package/templates/hooks/context-guardian.template.js +173 -0
  64. package/templates/hooks/deployment-orchestrator.template.js +219 -0
  65. package/templates/hooks/github-progress-hook.template.js +197 -0
  66. package/templates/hooks/happy-checkpoint-manager.template.js +222 -0
  67. package/templates/hooks/phase-dev-enforcer.template.js +183 -0
@@ -0,0 +1,392 @@
1
+ /**
2
+ * Decompose Command
3
+ *
4
+ * Break down a GitHub issue into granular, actionable tasks
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 { getIssue, addIssueComment } from '../github/client.js';
13
+ import { parseIssueBody, toClaudeTaskList, toMarkdownChecklist, getCompletionStats } from '../analysis/checklist-parser.js';
14
+ import { analyzeForIssue, searchFiles, findDefinitions } from '../analysis/codebase.js';
15
+ import { saveTaskState, loadTaskState } from './sync.js';
16
+
17
+ /**
18
+ * Run the decompose command
19
+ */
20
+ export async function runDecompose(options) {
21
+ showHeader('Decompose GitHub Issue');
22
+
23
+ // Load config
24
+ const { config } = loadConfigSync();
25
+ if (!config?.project_board?.owner) {
26
+ showError('Not configured', 'Run "gtask setup" first.');
27
+ return;
28
+ }
29
+
30
+ const { owner, repo } = config.project_board;
31
+
32
+ // Get issue number
33
+ let issueNumber = options.issue;
34
+ if (!issueNumber) {
35
+ const { num } = await inquirer.prompt([
36
+ {
37
+ type: 'input',
38
+ name: 'num',
39
+ message: 'Issue number to decompose:',
40
+ validate: (input) => {
41
+ const n = parseInt(input, 10);
42
+ return n > 0 ? true : 'Enter a valid issue number';
43
+ },
44
+ },
45
+ ]);
46
+ issueNumber = parseInt(num, 10);
47
+ }
48
+
49
+ // Fetch issue
50
+ const spinner = ora(`Fetching issue #${issueNumber}...`).start();
51
+ const issue = getIssue(owner, repo, issueNumber);
52
+
53
+ if (!issue) {
54
+ spinner.fail(`Issue #${issueNumber} not found`);
55
+ return;
56
+ }
57
+
58
+ spinner.succeed(`Fetched: ${issue.title}`);
59
+ console.log('');
60
+
61
+ // Parse existing issue body
62
+ const parseSpinner = ora('Parsing issue structure...').start();
63
+ const parsed = parseIssueBody(issue.body);
64
+ parseSpinner.stop();
65
+
66
+ // Show what we found
67
+ console.log(chalk.dim('Found in issue:'));
68
+ console.log(chalk.dim(` - ${parsed.todoList.length} existing todo items`));
69
+ console.log(chalk.dim(` - ${parsed.acceptanceCriteria.length} acceptance criteria`));
70
+ console.log(chalk.dim(` - ${parsed.testScenarios.length} test scenarios`));
71
+ console.log(chalk.dim(` - ${parsed.codeAnalysis.files.length} file references`));
72
+ console.log('');
73
+
74
+ // Decide decomposition strategy
75
+ const { strategy } = await inquirer.prompt([
76
+ {
77
+ type: 'list',
78
+ name: 'strategy',
79
+ message: 'How should we decompose this issue?',
80
+ choices: [
81
+ {
82
+ name: 'Use existing checklist + enhance with codebase analysis',
83
+ value: 'enhance',
84
+ },
85
+ {
86
+ name: 'Create new detailed breakdown (ignore existing)',
87
+ value: 'new',
88
+ },
89
+ {
90
+ name: 'Merge: combine existing + new analysis',
91
+ value: 'merge',
92
+ },
93
+ ],
94
+ },
95
+ ]);
96
+
97
+ let tasks = [];
98
+
99
+ if (strategy === 'enhance' || strategy === 'merge') {
100
+ // Start with existing todos
101
+ tasks = toClaudeTaskList(parsed);
102
+ console.log(chalk.green(`✓ Loaded ${tasks.length} existing tasks`));
103
+ }
104
+
105
+ if (strategy === 'new' || strategy === 'merge') {
106
+ // Perform codebase analysis
107
+ const analyzeSpinner = ora('Analyzing codebase...').start();
108
+
109
+ // Extract keywords from issue
110
+ const keywords = extractKeywords(issue.title, parsed.problemStatement);
111
+ const analysis = await analyzeForIssue(keywords, { maxFiles: 8 });
112
+
113
+ analyzeSpinner.succeed(
114
+ `Found ${analysis.relevantFiles.length} relevant files`
115
+ );
116
+
117
+ // Generate new tasks from analysis
118
+ const newTasks = generateTasksFromAnalysis(analysis, parsed, issue);
119
+
120
+ if (strategy === 'merge') {
121
+ // Deduplicate and merge
122
+ tasks = mergeTasks(tasks, newTasks);
123
+ console.log(chalk.green(`✓ Merged to ${tasks.length} total tasks`));
124
+ } else {
125
+ tasks = newTasks;
126
+ console.log(chalk.green(`✓ Generated ${tasks.length} new tasks`));
127
+ }
128
+ }
129
+
130
+ // Add standard tasks if missing
131
+ tasks = ensureStandardTasks(tasks);
132
+
133
+ // Show task preview
134
+ console.log('');
135
+ console.log(chalk.cyan('─'.repeat(60)));
136
+ console.log(chalk.bold('Task Breakdown Preview:'));
137
+ console.log(chalk.cyan('─'.repeat(60)));
138
+
139
+ for (let i = 0; i < tasks.length; i++) {
140
+ const task = tasks[i];
141
+ const status = task.status === 'completed' ? chalk.green('✓') : chalk.dim('○');
142
+ const num = chalk.dim(`${i + 1}.`);
143
+ console.log(`${status} ${num} ${task.content}`);
144
+
145
+ if (task.metadata?.fileRefs?.length > 0) {
146
+ const refs = task.metadata.fileRefs
147
+ .slice(0, 2)
148
+ .map((r) => `${r.file}${r.line ? ':' + r.line : ''}`)
149
+ .join(', ');
150
+ console.log(chalk.dim(` Files: ${refs}`));
151
+ }
152
+ }
153
+
154
+ console.log(chalk.cyan('─'.repeat(60)));
155
+ console.log('');
156
+
157
+ // Confirm and choose output
158
+ const { outputChoice } = await inquirer.prompt([
159
+ {
160
+ type: 'list',
161
+ name: 'outputChoice',
162
+ message: 'What would you like to do with this breakdown?',
163
+ choices: [
164
+ {
165
+ name: 'Save locally (for gtask sync later)',
166
+ value: 'local',
167
+ },
168
+ {
169
+ name: 'Post as comment on GitHub issue',
170
+ value: 'comment',
171
+ },
172
+ {
173
+ name: 'Both: save locally + post comment',
174
+ value: 'both',
175
+ },
176
+ {
177
+ name: 'Cancel',
178
+ value: 'cancel',
179
+ },
180
+ ],
181
+ },
182
+ ]);
183
+
184
+ if (outputChoice === 'cancel') {
185
+ console.log(chalk.yellow('Cancelled.'));
186
+ return;
187
+ }
188
+
189
+ // Save locally
190
+ if (outputChoice === 'local' || outputChoice === 'both') {
191
+ const state = {
192
+ issueNumber,
193
+ issueTitle: issue.title,
194
+ owner,
195
+ repo,
196
+ tasks,
197
+ createdAt: new Date().toISOString(),
198
+ lastSyncedAt: null,
199
+ };
200
+
201
+ saveTaskState(state);
202
+ console.log(chalk.green('✓ Saved locally'));
203
+ }
204
+
205
+ // Post to GitHub
206
+ if (outputChoice === 'comment' || outputChoice === 'both') {
207
+ const commentSpinner = ora('Posting to GitHub...').start();
208
+
209
+ const commentBody = generateDecomposeComment(tasks, strategy);
210
+ const success = addIssueComment(owner, repo, issueNumber, commentBody);
211
+
212
+ if (success) {
213
+ commentSpinner.succeed('Posted task breakdown to GitHub');
214
+ } else {
215
+ commentSpinner.fail('Failed to post comment');
216
+ }
217
+ }
218
+
219
+ // Summary
220
+ const stats = getCompletionStats(tasks);
221
+ showSuccess('Decomposition Complete', [
222
+ `Issue: #${issueNumber} - ${issue.title}`,
223
+ `Tasks: ${stats.total} (${stats.completed} completed, ${stats.pending} pending)`,
224
+ '',
225
+ 'Next steps:',
226
+ ` gtask sync ${issueNumber} - Sync progress to GitHub`,
227
+ ` gtask sync watch ${issueNumber} - Auto-sync on changes`,
228
+ ]);
229
+
230
+ return { issueNumber, tasks };
231
+ }
232
+
233
+ /**
234
+ * Extract keywords from title and description
235
+ */
236
+ function extractKeywords(title, description) {
237
+ const text = `${title} ${description || ''}`.toLowerCase();
238
+ const stopWords = new Set([
239
+ 'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'have', 'has',
240
+ 'do', 'does', 'did', 'will', 'would', 'could', 'should', 'may', 'might',
241
+ 'to', 'of', 'in', 'for', 'on', 'with', 'at', 'by', 'from', 'as', 'and',
242
+ 'but', 'or', 'not', 'this', 'that', 'it', 'bug', 'fix', 'issue', 'error',
243
+ ]);
244
+
245
+ return text
246
+ .replace(/[^a-z0-9\s]/g, ' ')
247
+ .split(/\s+/)
248
+ .filter((w) => w.length > 2 && !stopWords.has(w))
249
+ .slice(0, 10);
250
+ }
251
+
252
+ /**
253
+ * Generate tasks from codebase analysis
254
+ */
255
+ function generateTasksFromAnalysis(analysis, parsed, issue) {
256
+ const tasks = [];
257
+
258
+ // Task 1: Understand the problem
259
+ tasks.push({
260
+ content: 'Review issue and understand the problem',
261
+ activeForm: 'Reviewing issue and understanding the problem',
262
+ status: 'pending',
263
+ metadata: { type: 'research' },
264
+ });
265
+
266
+ // Tasks for each relevant file
267
+ for (const fileInfo of analysis.relevantFiles.slice(0, 5)) {
268
+ const file = fileInfo.file;
269
+ const mainFunc = fileInfo.definitions?.[0];
270
+
271
+ if (mainFunc) {
272
+ tasks.push({
273
+ content: `Review ${mainFunc.name}() in ${file}`,
274
+ activeForm: `Reviewing ${mainFunc.name}() in ${file}`,
275
+ status: 'pending',
276
+ metadata: {
277
+ type: 'review',
278
+ fileRefs: [{ file, line: mainFunc.line }],
279
+ functionRefs: [mainFunc.name],
280
+ },
281
+ });
282
+ } else {
283
+ tasks.push({
284
+ content: `Analyze ${file} for relevant code`,
285
+ activeForm: `Analyzing ${file}`,
286
+ status: 'pending',
287
+ metadata: {
288
+ type: 'review',
289
+ fileRefs: [{ file, line: null }],
290
+ },
291
+ });
292
+ }
293
+ }
294
+
295
+ // Task for implementation
296
+ tasks.push({
297
+ content: 'Implement the fix/feature',
298
+ activeForm: 'Implementing the fix/feature',
299
+ status: 'pending',
300
+ metadata: { type: 'implementation' },
301
+ });
302
+
303
+ // Tasks from acceptance criteria
304
+ for (const criterion of parsed.acceptanceCriteria.slice(0, 3)) {
305
+ tasks.push({
306
+ content: `Verify: ${criterion.text}`,
307
+ activeForm: `Verifying: ${criterion.text}`,
308
+ status: criterion.completed ? 'completed' : 'pending',
309
+ metadata: { type: 'verification' },
310
+ });
311
+ }
312
+
313
+ return tasks;
314
+ }
315
+
316
+ /**
317
+ * Merge two task lists, avoiding duplicates
318
+ */
319
+ function mergeTasks(existing, newTasks) {
320
+ const merged = [...existing];
321
+ const existingTexts = new Set(
322
+ existing.map((t) => t.content.toLowerCase())
323
+ );
324
+
325
+ for (const task of newTasks) {
326
+ const textLower = task.content.toLowerCase();
327
+ // Check for similar tasks
328
+ const isDuplicate = [...existingTexts].some(
329
+ (t) => t.includes(textLower) || textLower.includes(t)
330
+ );
331
+
332
+ if (!isDuplicate) {
333
+ merged.push(task);
334
+ existingTexts.add(textLower);
335
+ }
336
+ }
337
+
338
+ return merged;
339
+ }
340
+
341
+ /**
342
+ * Ensure standard tasks are present
343
+ */
344
+ function ensureStandardTasks(tasks) {
345
+ const hasTest = tasks.some(
346
+ (t) => t.content.toLowerCase().includes('test')
347
+ );
348
+ const hasCommit = tasks.some(
349
+ (t) => t.content.toLowerCase().includes('commit')
350
+ );
351
+
352
+ if (!hasTest) {
353
+ tasks.push({
354
+ content: 'Test changes locally',
355
+ activeForm: 'Testing changes locally',
356
+ status: 'pending',
357
+ metadata: { type: 'testing' },
358
+ });
359
+ }
360
+
361
+ if (!hasCommit) {
362
+ tasks.push({
363
+ content: 'Commit changes with descriptive message',
364
+ activeForm: 'Committing changes',
365
+ status: 'pending',
366
+ metadata: { type: 'commit' },
367
+ });
368
+ }
369
+
370
+ return tasks;
371
+ }
372
+
373
+ /**
374
+ * Generate comment body for GitHub
375
+ */
376
+ function generateDecomposeComment(tasks, strategy) {
377
+ const stats = getCompletionStats(tasks);
378
+ const checklist = toMarkdownChecklist(tasks);
379
+
380
+ return `## Task Breakdown
381
+
382
+ **Strategy**: ${strategy === 'enhance' ? 'Enhanced from existing checklist' : strategy === 'new' ? 'New analysis' : 'Merged existing + new'}
383
+ **Tasks**: ${stats.total} total (${stats.completed} done, ${stats.pending} pending)
384
+ **Progress**: ${stats.percentage}%
385
+
386
+ ### Detailed Tasks
387
+
388
+ ${checklist}
389
+
390
+ ---
391
+ *Generated by GitHub Task Kit - Use \`gtask sync ${stats.total > 0 ? 'watch' : ''}\` to track progress*`;
392
+ }