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,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setup Command
|
|
3
|
+
*
|
|
4
|
+
* Interactive wizard to configure GitHub project connection
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import inquirer from 'inquirer';
|
|
9
|
+
import ora from 'ora';
|
|
10
|
+
import { writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
11
|
+
import { join, dirname } from 'path';
|
|
12
|
+
import { stringify as yamlStringify } from 'yaml';
|
|
13
|
+
import { showHeader, showSuccess, showError, showWarning } from '../cli/menu.js';
|
|
14
|
+
import {
|
|
15
|
+
getCurrentUser,
|
|
16
|
+
listRepos,
|
|
17
|
+
repoExists,
|
|
18
|
+
listProjects,
|
|
19
|
+
getProject,
|
|
20
|
+
listProjectFields,
|
|
21
|
+
getAllFieldOptions,
|
|
22
|
+
} from '../github/client.js';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Run the setup wizard
|
|
26
|
+
*/
|
|
27
|
+
export async function runSetup(options) {
|
|
28
|
+
showHeader('GitHub Project Setup');
|
|
29
|
+
|
|
30
|
+
const config = {
|
|
31
|
+
project_board: {},
|
|
32
|
+
field_ids: {},
|
|
33
|
+
status_options: {},
|
|
34
|
+
priority_options: {},
|
|
35
|
+
labels: {
|
|
36
|
+
type: ['bug', 'feature', 'feature-update', 'refactor', 'documentation'],
|
|
37
|
+
stack: ['frontend', 'backend'],
|
|
38
|
+
priority: ['P0-Critical', 'P1-High', 'P2-Medium', 'P3-Low'],
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Step 1: Get current user
|
|
43
|
+
const spinner = ora('Checking GitHub authentication...').start();
|
|
44
|
+
const currentUser = getCurrentUser();
|
|
45
|
+
|
|
46
|
+
if (!currentUser) {
|
|
47
|
+
spinner.fail('Not authenticated with GitHub');
|
|
48
|
+
console.log('');
|
|
49
|
+
console.log(chalk.yellow('Run: gh auth login'));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
spinner.succeed(`Authenticated as ${chalk.bold(currentUser)}`);
|
|
54
|
+
console.log('');
|
|
55
|
+
|
|
56
|
+
// Step 2: Select owner (user or org)
|
|
57
|
+
let owner = options.owner;
|
|
58
|
+
|
|
59
|
+
if (!owner) {
|
|
60
|
+
const { ownerChoice } = await inquirer.prompt([
|
|
61
|
+
{
|
|
62
|
+
type: 'list',
|
|
63
|
+
name: 'ownerChoice',
|
|
64
|
+
message: 'GitHub owner (user or organization):',
|
|
65
|
+
choices: [
|
|
66
|
+
{ name: `${currentUser} (your account)`, value: currentUser },
|
|
67
|
+
{ name: 'Enter different owner...', value: '_other' },
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
]);
|
|
71
|
+
|
|
72
|
+
if (ownerChoice === '_other') {
|
|
73
|
+
const { customOwner } = await inquirer.prompt([
|
|
74
|
+
{
|
|
75
|
+
type: 'input',
|
|
76
|
+
name: 'customOwner',
|
|
77
|
+
message: 'Enter GitHub username or organization:',
|
|
78
|
+
validate: (input) => (input.trim() ? true : 'Owner is required'),
|
|
79
|
+
},
|
|
80
|
+
]);
|
|
81
|
+
owner = customOwner.trim();
|
|
82
|
+
} else {
|
|
83
|
+
owner = ownerChoice;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
config.project_board.owner = owner;
|
|
88
|
+
console.log('');
|
|
89
|
+
|
|
90
|
+
// Step 3: Select repository
|
|
91
|
+
let repo = options.repo;
|
|
92
|
+
|
|
93
|
+
if (!repo) {
|
|
94
|
+
const repoSpinner = ora(`Fetching repositories for ${owner}...`).start();
|
|
95
|
+
const repos = listRepos(owner, { limit: 50 });
|
|
96
|
+
repoSpinner.stop();
|
|
97
|
+
|
|
98
|
+
if (repos.length === 0) {
|
|
99
|
+
showWarning(`No repositories found for ${owner}`);
|
|
100
|
+
const { customRepo } = await inquirer.prompt([
|
|
101
|
+
{
|
|
102
|
+
type: 'input',
|
|
103
|
+
name: 'customRepo',
|
|
104
|
+
message: 'Enter repository name:',
|
|
105
|
+
validate: (input) => (input.trim() ? true : 'Repository is required'),
|
|
106
|
+
},
|
|
107
|
+
]);
|
|
108
|
+
repo = customRepo.trim();
|
|
109
|
+
} else {
|
|
110
|
+
const repoChoices = repos.map((r) => ({
|
|
111
|
+
name: `${r.name}${r.isPrivate ? chalk.dim(' (private)') : ''} ${
|
|
112
|
+
r.description ? chalk.dim('- ' + r.description.slice(0, 40)) : ''
|
|
113
|
+
}`,
|
|
114
|
+
value: r.name,
|
|
115
|
+
}));
|
|
116
|
+
repoChoices.push({ name: 'Enter manually...', value: '_other' });
|
|
117
|
+
|
|
118
|
+
const { repoChoice } = await inquirer.prompt([
|
|
119
|
+
{
|
|
120
|
+
type: 'list',
|
|
121
|
+
name: 'repoChoice',
|
|
122
|
+
message: 'Select repository:',
|
|
123
|
+
choices: repoChoices,
|
|
124
|
+
pageSize: 15,
|
|
125
|
+
},
|
|
126
|
+
]);
|
|
127
|
+
|
|
128
|
+
if (repoChoice === '_other') {
|
|
129
|
+
const { customRepo } = await inquirer.prompt([
|
|
130
|
+
{
|
|
131
|
+
type: 'input',
|
|
132
|
+
name: 'customRepo',
|
|
133
|
+
message: 'Enter repository name:',
|
|
134
|
+
validate: (input) => (input.trim() ? true : 'Repository is required'),
|
|
135
|
+
},
|
|
136
|
+
]);
|
|
137
|
+
repo = customRepo.trim();
|
|
138
|
+
} else {
|
|
139
|
+
repo = repoChoice;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Verify repo access
|
|
145
|
+
const verifySpinner = ora(`Verifying access to ${owner}/${repo}...`).start();
|
|
146
|
+
if (!repoExists(owner, repo)) {
|
|
147
|
+
verifySpinner.fail(`Cannot access ${owner}/${repo}`);
|
|
148
|
+
console.log(
|
|
149
|
+
chalk.yellow('Check that the repository exists and you have access.')
|
|
150
|
+
);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
verifySpinner.succeed(`Repository ${owner}/${repo} accessible`);
|
|
154
|
+
|
|
155
|
+
config.project_board.repo = repo;
|
|
156
|
+
console.log('');
|
|
157
|
+
|
|
158
|
+
// Step 4: Select project board
|
|
159
|
+
let projectNumber = options.project ? parseInt(options.project, 10) : null;
|
|
160
|
+
|
|
161
|
+
if (!projectNumber) {
|
|
162
|
+
const projectSpinner = ora(`Fetching projects for ${owner}...`).start();
|
|
163
|
+
const projects = listProjects(owner);
|
|
164
|
+
projectSpinner.stop();
|
|
165
|
+
|
|
166
|
+
if (projects.length === 0) {
|
|
167
|
+
showWarning(`No projects found for ${owner}`);
|
|
168
|
+
console.log(
|
|
169
|
+
chalk.dim('Create a project at: https://github.com/users/' + owner + '/projects')
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
const { customProject } = await inquirer.prompt([
|
|
173
|
+
{
|
|
174
|
+
type: 'input',
|
|
175
|
+
name: 'customProject',
|
|
176
|
+
message: 'Enter project number (or press Enter to skip):',
|
|
177
|
+
},
|
|
178
|
+
]);
|
|
179
|
+
|
|
180
|
+
if (customProject.trim()) {
|
|
181
|
+
projectNumber = parseInt(customProject.trim(), 10);
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
const projectChoices = projects.map((p) => ({
|
|
185
|
+
name: `#${p.number} - ${p.title}`,
|
|
186
|
+
value: p.number,
|
|
187
|
+
}));
|
|
188
|
+
projectChoices.push({ name: 'Skip project board setup', value: null });
|
|
189
|
+
|
|
190
|
+
const { projectChoice } = await inquirer.prompt([
|
|
191
|
+
{
|
|
192
|
+
type: 'list',
|
|
193
|
+
name: 'projectChoice',
|
|
194
|
+
message: 'Select project board:',
|
|
195
|
+
choices: projectChoices,
|
|
196
|
+
},
|
|
197
|
+
]);
|
|
198
|
+
|
|
199
|
+
projectNumber = projectChoice;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (projectNumber) {
|
|
204
|
+
config.project_board.project_number = projectNumber;
|
|
205
|
+
|
|
206
|
+
// Get project ID
|
|
207
|
+
const projectSpinner = ora('Fetching project details...').start();
|
|
208
|
+
const project = getProject(owner, projectNumber);
|
|
209
|
+
|
|
210
|
+
if (project) {
|
|
211
|
+
config.project_board.project_id = project.id;
|
|
212
|
+
projectSpinner.succeed(`Project: ${project.title}`);
|
|
213
|
+
|
|
214
|
+
// Step 5: Get field IDs
|
|
215
|
+
console.log('');
|
|
216
|
+
const fieldSpinner = ora('Analyzing project fields...').start();
|
|
217
|
+
const fields = listProjectFields(owner, projectNumber);
|
|
218
|
+
fieldSpinner.stop();
|
|
219
|
+
|
|
220
|
+
if (fields.length > 0) {
|
|
221
|
+
console.log(chalk.dim('Found fields:'));
|
|
222
|
+
for (const field of fields) {
|
|
223
|
+
console.log(chalk.dim(` - ${field.name} (${field.id})`));
|
|
224
|
+
}
|
|
225
|
+
console.log('');
|
|
226
|
+
|
|
227
|
+
// Auto-detect common fields
|
|
228
|
+
const statusField = fields.find(
|
|
229
|
+
(f) => f.name.toLowerCase() === 'status'
|
|
230
|
+
);
|
|
231
|
+
const priorityField = fields.find(
|
|
232
|
+
(f) =>
|
|
233
|
+
f.name.toLowerCase() === 'priority' ||
|
|
234
|
+
f.name.toLowerCase().includes('priority')
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
if (statusField) {
|
|
238
|
+
config.field_ids.status = statusField.id;
|
|
239
|
+
console.log(chalk.green(`✓ Status field: ${statusField.id}`));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (priorityField) {
|
|
243
|
+
config.field_ids.priority = priorityField.id;
|
|
244
|
+
console.log(chalk.green(`✓ Priority field: ${priorityField.id}`));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Get field options via GraphQL
|
|
248
|
+
console.log('');
|
|
249
|
+
const optionsSpinner = ora('Fetching field options...').start();
|
|
250
|
+
const allFieldOptions = getAllFieldOptions(project.id);
|
|
251
|
+
optionsSpinner.stop();
|
|
252
|
+
|
|
253
|
+
for (const field of allFieldOptions) {
|
|
254
|
+
if (field.options && field.options.length > 0) {
|
|
255
|
+
console.log(chalk.dim(`\n${field.name} options:`));
|
|
256
|
+
for (const opt of field.options) {
|
|
257
|
+
console.log(chalk.dim(` - ${opt.name}: ${opt.id}`));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Auto-map status options
|
|
261
|
+
if (field.name.toLowerCase() === 'status') {
|
|
262
|
+
for (const opt of field.options) {
|
|
263
|
+
const optLower = opt.name.toLowerCase();
|
|
264
|
+
if (optLower === 'todo' || optLower === 'to do') {
|
|
265
|
+
config.status_options.todo = opt.id;
|
|
266
|
+
} else if (
|
|
267
|
+
optLower === 'in progress' ||
|
|
268
|
+
optLower === 'in_progress'
|
|
269
|
+
) {
|
|
270
|
+
config.status_options.in_progress = opt.id;
|
|
271
|
+
} else if (optLower === 'done' || optLower === 'completed') {
|
|
272
|
+
config.status_options.done = opt.id;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Auto-map priority options
|
|
278
|
+
if (
|
|
279
|
+
field.name.toLowerCase() === 'priority' ||
|
|
280
|
+
field.name.toLowerCase().includes('priority')
|
|
281
|
+
) {
|
|
282
|
+
for (const opt of field.options) {
|
|
283
|
+
const optLower = opt.name.toLowerCase();
|
|
284
|
+
if (optLower.includes('p0') || optLower.includes('critical')) {
|
|
285
|
+
config.priority_options.p0 = opt.id;
|
|
286
|
+
} else if (optLower.includes('p1') || optLower.includes('high')) {
|
|
287
|
+
config.priority_options.p1 = opt.id;
|
|
288
|
+
} else if (optLower.includes('p2') || optLower.includes('medium')) {
|
|
289
|
+
config.priority_options.p2 = opt.id;
|
|
290
|
+
} else if (optLower.includes('p3') || optLower.includes('low')) {
|
|
291
|
+
config.priority_options.p3 = opt.id;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
projectSpinner.warn('Could not fetch project details');
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
console.log('');
|
|
304
|
+
|
|
305
|
+
// Step 6: Choose config location
|
|
306
|
+
const { configLocation } = await inquirer.prompt([
|
|
307
|
+
{
|
|
308
|
+
type: 'list',
|
|
309
|
+
name: 'configLocation',
|
|
310
|
+
message: 'Where should we save the configuration?',
|
|
311
|
+
choices: [
|
|
312
|
+
{
|
|
313
|
+
name: `${process.cwd()}/.gtaskrc ${chalk.dim('(project-local)')}`,
|
|
314
|
+
value: 'local',
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
name: `~/.gtaskrc ${chalk.dim('(global, all projects)')}`,
|
|
318
|
+
value: 'global',
|
|
319
|
+
},
|
|
320
|
+
],
|
|
321
|
+
},
|
|
322
|
+
]);
|
|
323
|
+
|
|
324
|
+
// Determine path
|
|
325
|
+
const configPath =
|
|
326
|
+
configLocation === 'global'
|
|
327
|
+
? join(process.env.HOME || process.env.USERPROFILE || '', '.gtaskrc')
|
|
328
|
+
: join(process.cwd(), '.gtaskrc');
|
|
329
|
+
|
|
330
|
+
// Write config
|
|
331
|
+
const saveSpinner = ora(`Saving configuration to ${configPath}...`).start();
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
const yamlContent = yamlStringify(config);
|
|
335
|
+
writeFileSync(configPath, yamlContent, 'utf8');
|
|
336
|
+
saveSpinner.succeed('Configuration saved');
|
|
337
|
+
} catch (error) {
|
|
338
|
+
saveSpinner.fail(`Failed to save: ${error.message}`);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Summary
|
|
343
|
+
showSuccess('Setup Complete!', [
|
|
344
|
+
`Owner: ${config.project_board.owner}`,
|
|
345
|
+
`Repo: ${config.project_board.repo}`,
|
|
346
|
+
`Project: #${config.project_board.project_number || 'none'}`,
|
|
347
|
+
`Config: ${configPath}`,
|
|
348
|
+
'',
|
|
349
|
+
'Run "gtask create" to create your first task!',
|
|
350
|
+
]);
|
|
351
|
+
}
|