claude-cli-advanced-starter-pack 1.0.4 → 1.0.7
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/README.md +69 -5
- package/package.json +69 -69
- package/src/commands/init.js +315 -37
- package/src/commands/setup-wizard.js +736 -110
- package/src/data/releases.json +349 -0
- package/src/utils/version-check.js +512 -0
- package/templates/commands/project-impl.template.md +320 -0
- package/templates/commands/update-check.template.md +322 -0
- package/templates/hooks/ccasp-update-check.template.js +241 -0
|
@@ -10,13 +10,27 @@ import chalk from 'chalk';
|
|
|
10
10
|
import ora from 'ora';
|
|
11
11
|
import boxen from 'boxen';
|
|
12
12
|
import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, rmSync, renameSync, copyFileSync } from 'fs';
|
|
13
|
-
import { join, basename } from 'path';
|
|
13
|
+
import { join, basename, dirname } from 'path';
|
|
14
|
+
import { fileURLToPath } from 'url';
|
|
14
15
|
import { runInit } from './init.js';
|
|
15
16
|
import { detectTechStack } from './detect-tech-stack.js';
|
|
16
|
-
import {
|
|
17
|
+
import { runEnhancement } from './claude-audit.js';
|
|
17
18
|
import { runSetup as runGitHubSetup } from './setup.js';
|
|
18
19
|
import { runList } from './list.js';
|
|
19
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
performVersionCheck,
|
|
22
|
+
formatUpdateBanner,
|
|
23
|
+
loadReleaseNotes,
|
|
24
|
+
getReleasesSince,
|
|
25
|
+
getAvailableFeatures,
|
|
26
|
+
markFeatureInstalled,
|
|
27
|
+
markFeatureSkipped,
|
|
28
|
+
dismissUpdateNotification,
|
|
29
|
+
getCurrentVersion,
|
|
30
|
+
} from '../utils/version-check.js';
|
|
31
|
+
|
|
32
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
33
|
+
const __dirname = dirname(__filename);
|
|
20
34
|
|
|
21
35
|
/**
|
|
22
36
|
* Create backup of a file before overwriting
|
|
@@ -39,15 +53,189 @@ export function createBackup(filePath) {
|
|
|
39
53
|
return backupPath;
|
|
40
54
|
}
|
|
41
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Find existing CCASP backups in the project
|
|
58
|
+
*/
|
|
59
|
+
function findExistingBackups() {
|
|
60
|
+
const backupDir = join(process.cwd(), '.claude-backup');
|
|
61
|
+
const backups = [];
|
|
62
|
+
|
|
63
|
+
if (!existsSync(backupDir)) {
|
|
64
|
+
return backups;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const entries = readdirSync(backupDir, { withFileTypes: true });
|
|
69
|
+
for (const entry of entries) {
|
|
70
|
+
if (entry.isDirectory()) {
|
|
71
|
+
const backupPath = join(backupDir, entry.name);
|
|
72
|
+
const hasClaudeDir = existsSync(join(backupPath, '.claude'));
|
|
73
|
+
const hasClaudeMd = existsSync(join(backupPath, 'CLAUDE.md'));
|
|
74
|
+
|
|
75
|
+
if (hasClaudeDir || hasClaudeMd) {
|
|
76
|
+
// Parse timestamp from folder name (format: 2025-01-30T12-30-45)
|
|
77
|
+
let date = entry.name;
|
|
78
|
+
try {
|
|
79
|
+
const isoDate = entry.name.replace(/T(\d{2})-(\d{2})-(\d{2})/, 'T$1:$2:$3');
|
|
80
|
+
date = new Date(isoDate).toLocaleString();
|
|
81
|
+
} catch {
|
|
82
|
+
// Keep original name if parsing fails
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
backups.push({
|
|
86
|
+
name: entry.name,
|
|
87
|
+
path: backupPath,
|
|
88
|
+
date,
|
|
89
|
+
hasClaudeDir,
|
|
90
|
+
hasClaudeMd,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
} catch {
|
|
96
|
+
// Silently fail
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Sort by name (newest first)
|
|
100
|
+
return backups.sort((a, b) => b.name.localeCompare(a.name));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Restore from a backup
|
|
105
|
+
*/
|
|
106
|
+
async function runRestore(backups) {
|
|
107
|
+
if (backups.length === 0) {
|
|
108
|
+
console.log(chalk.yellow('\n⚠️ No backups found in .claude-backup/\n'));
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
console.log(chalk.bold('\n📦 Available backups:\n'));
|
|
113
|
+
|
|
114
|
+
const choices = backups.map((backup, index) => {
|
|
115
|
+
const contents = [];
|
|
116
|
+
if (backup.hasClaudeDir) contents.push('.claude/');
|
|
117
|
+
if (backup.hasClaudeMd) contents.push('CLAUDE.md');
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
name: `${chalk.yellow(`${index + 1}.`)} ${backup.date} ${chalk.dim(`(${contents.join(', ')})`)}`,
|
|
121
|
+
value: backup,
|
|
122
|
+
short: backup.date,
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
choices.push({
|
|
127
|
+
name: `${chalk.green('0.')} Cancel`,
|
|
128
|
+
value: null,
|
|
129
|
+
short: 'Cancel',
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const { selectedBackup } = await inquirer.prompt([
|
|
133
|
+
{
|
|
134
|
+
type: 'list',
|
|
135
|
+
name: 'selectedBackup',
|
|
136
|
+
message: 'Select a backup to restore:',
|
|
137
|
+
choices,
|
|
138
|
+
},
|
|
139
|
+
]);
|
|
140
|
+
|
|
141
|
+
if (!selectedBackup) {
|
|
142
|
+
console.log(chalk.dim('\nCancelled. No changes made.\n'));
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Confirm restore
|
|
147
|
+
const claudeDir = join(process.cwd(), '.claude');
|
|
148
|
+
const claudeMdPath = join(process.cwd(), 'CLAUDE.md');
|
|
149
|
+
const willOverwrite = [];
|
|
150
|
+
|
|
151
|
+
if (existsSync(claudeDir) && selectedBackup.hasClaudeDir) {
|
|
152
|
+
willOverwrite.push('.claude/');
|
|
153
|
+
}
|
|
154
|
+
if (existsSync(claudeMdPath) && selectedBackup.hasClaudeMd) {
|
|
155
|
+
willOverwrite.push('CLAUDE.md');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (willOverwrite.length > 0) {
|
|
159
|
+
console.log(chalk.yellow(`\n⚠️ This will overwrite: ${willOverwrite.join(', ')}`));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const { confirmRestore } = await inquirer.prompt([
|
|
163
|
+
{
|
|
164
|
+
type: 'confirm',
|
|
165
|
+
name: 'confirmRestore',
|
|
166
|
+
message: `Restore from backup "${selectedBackup.date}"?`,
|
|
167
|
+
default: true,
|
|
168
|
+
},
|
|
169
|
+
]);
|
|
170
|
+
|
|
171
|
+
if (!confirmRestore) {
|
|
172
|
+
console.log(chalk.dim('\nCancelled. No changes made.\n'));
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const spinner = ora('Restoring from backup...').start();
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
// Restore .claude folder
|
|
180
|
+
if (selectedBackup.hasClaudeDir) {
|
|
181
|
+
const backupClaudeDir = join(selectedBackup.path, '.claude');
|
|
182
|
+
if (existsSync(claudeDir)) {
|
|
183
|
+
rmSync(claudeDir, { recursive: true, force: true });
|
|
184
|
+
}
|
|
185
|
+
copyDirRecursive(backupClaudeDir, claudeDir);
|
|
186
|
+
spinner.text = 'Restored .claude folder...';
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Restore CLAUDE.md
|
|
190
|
+
if (selectedBackup.hasClaudeMd) {
|
|
191
|
+
const backupClaudeMd = join(selectedBackup.path, 'CLAUDE.md');
|
|
192
|
+
copyFileSync(backupClaudeMd, claudeMdPath);
|
|
193
|
+
spinner.text = 'Restored CLAUDE.md...';
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
spinner.succeed('Backup restored successfully!');
|
|
197
|
+
|
|
198
|
+
console.log(
|
|
199
|
+
boxen(
|
|
200
|
+
chalk.green('✅ Restored from backup\n\n') +
|
|
201
|
+
`Backup date: ${chalk.cyan(selectedBackup.date)}\n` +
|
|
202
|
+
(selectedBackup.hasClaudeDir ? ` • ${chalk.cyan('.claude/')} restored\n` : '') +
|
|
203
|
+
(selectedBackup.hasClaudeMd ? ` • ${chalk.cyan('CLAUDE.md')} restored\n` : '') +
|
|
204
|
+
'\n' +
|
|
205
|
+
chalk.dim('Restart Claude Code CLI to use restored configuration.'),
|
|
206
|
+
{
|
|
207
|
+
padding: 1,
|
|
208
|
+
borderStyle: 'round',
|
|
209
|
+
borderColor: 'green',
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
return true;
|
|
215
|
+
} catch (error) {
|
|
216
|
+
spinner.fail('Restore failed');
|
|
217
|
+
console.error(chalk.red(error.message));
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
42
222
|
/**
|
|
43
223
|
* Remove CCASP from a project
|
|
44
224
|
*/
|
|
45
225
|
async function runRemove() {
|
|
46
226
|
const claudeDir = join(process.cwd(), '.claude');
|
|
227
|
+
const claudeMdPath = join(process.cwd(), 'CLAUDE.md');
|
|
228
|
+
const existingBackups = findExistingBackups();
|
|
47
229
|
|
|
48
|
-
if
|
|
230
|
+
// Check if there's anything to work with
|
|
231
|
+
const hasClaudeDir = existsSync(claudeDir);
|
|
232
|
+
const hasClaudeMd = existsSync(claudeMdPath);
|
|
233
|
+
|
|
234
|
+
if (!hasClaudeDir && existingBackups.length === 0) {
|
|
49
235
|
console.log(chalk.yellow('\n⚠️ No .claude folder found in this project.\n'));
|
|
50
|
-
|
|
236
|
+
if (!hasClaudeMd) {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
51
239
|
}
|
|
52
240
|
|
|
53
241
|
// Show what will be removed
|
|
@@ -112,41 +300,67 @@ async function runRemove() {
|
|
|
112
300
|
}
|
|
113
301
|
}
|
|
114
302
|
|
|
115
|
-
|
|
303
|
+
// Check for CLAUDE.md in project root
|
|
304
|
+
if (hasClaudeMd) {
|
|
305
|
+
console.log(` ${chalk.cyan('CLAUDE.md')} ${chalk.dim('(project root)')}`);
|
|
306
|
+
itemsToRemove.push({ type: 'file', path: claudeMdPath, label: 'CLAUDE.md', isRoot: true });
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (itemsToRemove.length === 0 && existingBackups.length === 0) {
|
|
116
310
|
console.log(chalk.yellow(' No CCASP items found.\n'));
|
|
117
311
|
return false;
|
|
118
312
|
}
|
|
119
313
|
|
|
314
|
+
// Show existing backups count
|
|
315
|
+
if (existingBackups.length > 0) {
|
|
316
|
+
console.log(chalk.dim(`\n 📦 ${existingBackups.length} backup(s) available in .claude-backup/`));
|
|
317
|
+
}
|
|
318
|
+
|
|
120
319
|
console.log('');
|
|
121
320
|
|
|
122
|
-
// Removal options
|
|
321
|
+
// Removal options - dynamically build based on what exists
|
|
322
|
+
const removeChoices = [];
|
|
323
|
+
|
|
324
|
+
if (itemsToRemove.length > 0) {
|
|
325
|
+
removeChoices.push(
|
|
326
|
+
{
|
|
327
|
+
name: `${chalk.red('1.')} Remove ALL ${chalk.dim('- Delete .claude/ and CLAUDE.md')}`,
|
|
328
|
+
value: 'all',
|
|
329
|
+
short: 'Remove All',
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
name: `${chalk.yellow('2.')} Remove with backup ${chalk.dim('- Full backup to .claude-backup/ first')}`,
|
|
333
|
+
value: 'backup',
|
|
334
|
+
short: 'Backup & Remove',
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
name: `${chalk.cyan('3.')} Selective removal ${chalk.dim('- Choose what to remove')}`,
|
|
338
|
+
value: 'selective',
|
|
339
|
+
short: 'Selective',
|
|
340
|
+
}
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (existingBackups.length > 0) {
|
|
345
|
+
removeChoices.push({
|
|
346
|
+
name: `${chalk.green('4.')} Restore from backup ${chalk.dim(`- ${existingBackups.length} backup(s) available`)}`,
|
|
347
|
+
value: 'restore',
|
|
348
|
+
short: 'Restore',
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
removeChoices.push({
|
|
353
|
+
name: `${chalk.dim('0.')} Cancel ${chalk.dim('- Keep everything')}`,
|
|
354
|
+
value: 'cancel',
|
|
355
|
+
short: 'Cancel',
|
|
356
|
+
});
|
|
357
|
+
|
|
123
358
|
const { removeAction } = await inquirer.prompt([
|
|
124
359
|
{
|
|
125
360
|
type: 'list',
|
|
126
361
|
name: 'removeAction',
|
|
127
362
|
message: 'What would you like to do?',
|
|
128
|
-
choices:
|
|
129
|
-
{
|
|
130
|
-
name: `${chalk.red('1.')} Remove ALL ${chalk.dim('- Delete entire .claude folder')}`,
|
|
131
|
-
value: 'all',
|
|
132
|
-
short: 'Remove All',
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
name: `${chalk.yellow('2.')} Remove with backup ${chalk.dim('- Backup to .claude-backup/ first')}`,
|
|
136
|
-
value: 'backup',
|
|
137
|
-
short: 'Backup & Remove',
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
name: `${chalk.cyan('3.')} Selective removal ${chalk.dim('- Choose what to remove')}`,
|
|
141
|
-
value: 'selective',
|
|
142
|
-
short: 'Selective',
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
name: `${chalk.green('0.')} Cancel ${chalk.dim('- Keep everything')}`,
|
|
146
|
-
value: 'cancel',
|
|
147
|
-
short: 'Cancel',
|
|
148
|
-
},
|
|
149
|
-
],
|
|
363
|
+
choices: removeChoices,
|
|
150
364
|
},
|
|
151
365
|
]);
|
|
152
366
|
|
|
@@ -155,6 +369,11 @@ async function runRemove() {
|
|
|
155
369
|
return false;
|
|
156
370
|
}
|
|
157
371
|
|
|
372
|
+
// Handle restore action
|
|
373
|
+
if (removeAction === 'restore') {
|
|
374
|
+
return await runRestore(existingBackups);
|
|
375
|
+
}
|
|
376
|
+
|
|
158
377
|
if (removeAction === 'backup' || removeAction === 'all') {
|
|
159
378
|
// Confirm dangerous action
|
|
160
379
|
const { confirmRemove } = await inquirer.prompt([
|
|
@@ -176,24 +395,49 @@ async function runRemove() {
|
|
|
176
395
|
|
|
177
396
|
try {
|
|
178
397
|
if (removeAction === 'backup') {
|
|
179
|
-
// Create backup first
|
|
180
|
-
const
|
|
398
|
+
// Create backup first - include timestamp folder
|
|
399
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
400
|
+
const backupDir = join(process.cwd(), '.claude-backup', timestamp);
|
|
181
401
|
mkdirSync(backupDir, { recursive: true });
|
|
182
402
|
|
|
183
|
-
// Copy entire .claude folder to backup
|
|
184
|
-
|
|
403
|
+
// Copy entire .claude folder to backup (nested under .claude/)
|
|
404
|
+
if (hasClaudeDir) {
|
|
405
|
+
const backupClaudeDir = join(backupDir, '.claude');
|
|
406
|
+
copyDirRecursive(claudeDir, backupClaudeDir);
|
|
407
|
+
spinner.text = 'Backed up .claude folder...';
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Also backup CLAUDE.md if it exists
|
|
411
|
+
if (hasClaudeMd) {
|
|
412
|
+
copyFileSync(claudeMdPath, join(backupDir, 'CLAUDE.md'));
|
|
413
|
+
spinner.text = 'Backed up CLAUDE.md...';
|
|
414
|
+
}
|
|
415
|
+
|
|
185
416
|
spinner.succeed(`Backed up to ${chalk.cyan(backupDir)}`);
|
|
186
417
|
|
|
187
|
-
// Then remove
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
418
|
+
// Then remove .claude folder
|
|
419
|
+
if (hasClaudeDir) {
|
|
420
|
+
spinner.start('Removing .claude folder...');
|
|
421
|
+
rmSync(claudeDir, { recursive: true, force: true });
|
|
422
|
+
spinner.succeed('.claude folder removed');
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Remove CLAUDE.md
|
|
426
|
+
if (hasClaudeMd) {
|
|
427
|
+
spinner.start('Removing CLAUDE.md...');
|
|
428
|
+
rmSync(claudeMdPath, { force: true });
|
|
429
|
+
spinner.succeed('CLAUDE.md removed');
|
|
430
|
+
}
|
|
191
431
|
|
|
192
432
|
console.log(
|
|
193
433
|
boxen(
|
|
194
|
-
chalk.green('✅ CCASP removed with backup\n\n') +
|
|
434
|
+
chalk.green('✅ CCASP removed with full backup\n\n') +
|
|
195
435
|
`Backup location:\n${chalk.cyan(backupDir)}\n\n` +
|
|
196
|
-
chalk.
|
|
436
|
+
chalk.bold('Contents backed up:\n') +
|
|
437
|
+
(hasClaudeDir ? ` • ${chalk.cyan('.claude/')} folder\n` : '') +
|
|
438
|
+
(hasClaudeMd ? ` • ${chalk.cyan('CLAUDE.md')} file\n` : '') +
|
|
439
|
+
'\n' +
|
|
440
|
+
chalk.dim('To restore: run ') + chalk.cyan('ccasp wizard') + chalk.dim(' → Remove CCASP → Restore'),
|
|
197
441
|
{
|
|
198
442
|
padding: 1,
|
|
199
443
|
borderStyle: 'round',
|
|
@@ -203,12 +447,22 @@ async function runRemove() {
|
|
|
203
447
|
);
|
|
204
448
|
} else if (removeAction === 'all') {
|
|
205
449
|
// Remove without backup
|
|
206
|
-
|
|
207
|
-
|
|
450
|
+
if (hasClaudeDir) {
|
|
451
|
+
rmSync(claudeDir, { recursive: true, force: true });
|
|
452
|
+
spinner.text = '.claude folder removed...';
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (hasClaudeMd) {
|
|
456
|
+
rmSync(claudeMdPath, { force: true });
|
|
457
|
+
spinner.text = 'CLAUDE.md removed...';
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
spinner.succeed('CCASP files removed');
|
|
208
461
|
|
|
209
462
|
console.log(
|
|
210
463
|
boxen(
|
|
211
464
|
chalk.green('✅ CCASP removed\n\n') +
|
|
465
|
+
chalk.yellow('⚠️ No backup was created.\n\n') +
|
|
212
466
|
chalk.dim('Run ') + chalk.cyan('ccasp wizard') + chalk.dim(' to set up again.'),
|
|
213
467
|
{
|
|
214
468
|
padding: 1,
|
|
@@ -226,8 +480,8 @@ async function runRemove() {
|
|
|
226
480
|
type: 'checkbox',
|
|
227
481
|
name: 'itemsToDelete',
|
|
228
482
|
message: 'Select items to remove:',
|
|
229
|
-
choices: itemsToRemove.map(item => ({
|
|
230
|
-
name: item.label,
|
|
483
|
+
choices: itemsToRemove.map((item) => ({
|
|
484
|
+
name: item.isRoot ? `${item.label} ${chalk.dim('(project root)')}` : item.label,
|
|
231
485
|
value: item,
|
|
232
486
|
checked: false,
|
|
233
487
|
})),
|
|
@@ -239,22 +493,44 @@ async function runRemove() {
|
|
|
239
493
|
return false;
|
|
240
494
|
}
|
|
241
495
|
|
|
242
|
-
// Create backups for selected items
|
|
243
|
-
|
|
244
|
-
|
|
496
|
+
// Create backups for selected items in .claude-backup/ (not .claude/backups/)
|
|
497
|
+
// This ensures backups survive if user removes entire .claude folder
|
|
498
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
499
|
+
const backupDir = join(process.cwd(), '.claude-backup', `selective-${timestamp}`);
|
|
500
|
+
const backupClaudeDir = join(backupDir, '.claude');
|
|
501
|
+
mkdirSync(backupClaudeDir, { recursive: true });
|
|
245
502
|
|
|
246
503
|
for (const item of itemsToDelete) {
|
|
504
|
+
// Determine backup destination - CLAUDE.md goes to backup root, others under .claude/
|
|
505
|
+
const backupDest = item.isRoot ? join(backupDir, basename(item.path)) : join(backupClaudeDir, basename(item.path));
|
|
506
|
+
|
|
247
507
|
if (item.type === 'dir') {
|
|
248
|
-
copyDirRecursive(item.path,
|
|
508
|
+
copyDirRecursive(item.path, backupDest);
|
|
249
509
|
rmSync(item.path, { recursive: true, force: true });
|
|
250
510
|
} else {
|
|
251
|
-
|
|
511
|
+
// Ensure parent directory exists
|
|
512
|
+
const parentDir = dirname(backupDest);
|
|
513
|
+
if (!existsSync(parentDir)) {
|
|
514
|
+
mkdirSync(parentDir, { recursive: true });
|
|
515
|
+
}
|
|
516
|
+
copyFileSync(item.path, backupDest);
|
|
252
517
|
rmSync(item.path, { force: true });
|
|
253
518
|
}
|
|
254
519
|
console.log(` ${chalk.red('✗')} Removed ${item.label}`);
|
|
255
520
|
}
|
|
256
521
|
|
|
257
|
-
console.log(
|
|
522
|
+
console.log(
|
|
523
|
+
boxen(
|
|
524
|
+
chalk.green('✅ Selected items removed\n\n') +
|
|
525
|
+
`Backup location:\n${chalk.cyan(backupDir)}\n\n` +
|
|
526
|
+
chalk.dim('To restore: run ') + chalk.cyan('ccasp wizard') + chalk.dim(' → Remove CCASP → Restore'),
|
|
527
|
+
{
|
|
528
|
+
padding: 1,
|
|
529
|
+
borderStyle: 'round',
|
|
530
|
+
borderColor: 'green',
|
|
531
|
+
}
|
|
532
|
+
)
|
|
533
|
+
);
|
|
258
534
|
}
|
|
259
535
|
|
|
260
536
|
return true;
|
|
@@ -321,32 +597,17 @@ const SETUP_OPTIONS = [
|
|
|
321
597
|
short: 'GitHub',
|
|
322
598
|
},
|
|
323
599
|
{
|
|
324
|
-
name: `${chalk.yellow('4.')}
|
|
325
|
-
value: 'audit',
|
|
326
|
-
short: 'Audit',
|
|
327
|
-
},
|
|
328
|
-
{
|
|
329
|
-
name: `${chalk.yellow('5.')} Enhance CLAUDE.md ${chalk.dim('- Generate/improve docs')}`,
|
|
330
|
-
value: 'enhance',
|
|
331
|
-
short: 'Enhance',
|
|
332
|
-
},
|
|
333
|
-
{
|
|
334
|
-
name: `${chalk.yellow('6.')} Detect Tech Stack ${chalk.dim('- Auto-detect project')}`,
|
|
335
|
-
value: 'detect',
|
|
336
|
-
short: 'Detect',
|
|
337
|
-
},
|
|
338
|
-
{
|
|
339
|
-
name: `${chalk.yellow('7.')} View Templates ${chalk.dim('- Browse available items')}`,
|
|
600
|
+
name: `${chalk.yellow('4.')} View Templates ${chalk.dim('- Browse available items')}`,
|
|
340
601
|
value: 'templates',
|
|
341
602
|
short: 'Templates',
|
|
342
603
|
},
|
|
343
604
|
{
|
|
344
|
-
name: `${chalk.yellow('
|
|
345
|
-
value: '
|
|
346
|
-
short: '
|
|
605
|
+
name: `${chalk.yellow('5.')} Prior Releases ${chalk.dim('- Review & add features from past versions')}`,
|
|
606
|
+
value: 'releases',
|
|
607
|
+
short: 'Releases',
|
|
347
608
|
},
|
|
348
609
|
{
|
|
349
|
-
name: `${chalk.yellow('
|
|
610
|
+
name: `${chalk.yellow('6.')} Remove CCASP ${chalk.dim('- Uninstall from this project')}`,
|
|
350
611
|
value: 'remove',
|
|
351
612
|
short: 'Remove',
|
|
352
613
|
},
|
|
@@ -618,12 +879,407 @@ async function showTemplates() {
|
|
|
618
879
|
}
|
|
619
880
|
}
|
|
620
881
|
|
|
882
|
+
/**
|
|
883
|
+
* Show prior releases and allow adding features
|
|
884
|
+
*/
|
|
885
|
+
async function showPriorReleases() {
|
|
886
|
+
console.log(chalk.bold('\n📜 Prior Releases\n'));
|
|
887
|
+
|
|
888
|
+
const { releases } = loadReleaseNotes();
|
|
889
|
+
const currentVersion = getCurrentVersion();
|
|
890
|
+
|
|
891
|
+
if (!releases || releases.length === 0) {
|
|
892
|
+
console.log(chalk.yellow(' No release history available.\n'));
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
// Show release list
|
|
897
|
+
console.log(chalk.dim(' Select a release to view details and available features:\n'));
|
|
898
|
+
|
|
899
|
+
releases.forEach((release, i) => {
|
|
900
|
+
const isCurrent = release.version === currentVersion;
|
|
901
|
+
const marker = isCurrent ? chalk.green('●') : chalk.dim('○');
|
|
902
|
+
const currentLabel = isCurrent ? chalk.green(' (current)') : '';
|
|
903
|
+
console.log(` ${chalk.yellow(i + 1 + '.')} ${marker} v${release.version}${currentLabel} ${chalk.dim(`(${release.date})`)}`);
|
|
904
|
+
console.log(` ${chalk.dim(release.summary)}`);
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
console.log('');
|
|
908
|
+
|
|
909
|
+
const { releaseChoice } = await inquirer.prompt([
|
|
910
|
+
{
|
|
911
|
+
type: 'list',
|
|
912
|
+
name: 'releaseChoice',
|
|
913
|
+
message: 'Select a release to view details:',
|
|
914
|
+
choices: [
|
|
915
|
+
...releases.map((r, i) => ({
|
|
916
|
+
name: `${i + 1}. v${r.version} - ${r.summary}`,
|
|
917
|
+
value: i,
|
|
918
|
+
short: `v${r.version}`,
|
|
919
|
+
})),
|
|
920
|
+
{
|
|
921
|
+
name: `${chalk.cyan('A.')} Add available features to project`,
|
|
922
|
+
value: 'add',
|
|
923
|
+
short: 'Add Features',
|
|
924
|
+
},
|
|
925
|
+
{
|
|
926
|
+
name: `${chalk.dim('0.')} Back to menu`,
|
|
927
|
+
value: 'back',
|
|
928
|
+
short: 'Back',
|
|
929
|
+
},
|
|
930
|
+
],
|
|
931
|
+
pageSize: 12,
|
|
932
|
+
},
|
|
933
|
+
]);
|
|
934
|
+
|
|
935
|
+
if (releaseChoice === 'back') {
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
if (releaseChoice === 'add') {
|
|
940
|
+
await showAddFeaturesMenu();
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
// Show release details
|
|
945
|
+
const release = releases[releaseChoice];
|
|
946
|
+
await showReleaseDetails(release);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
/**
|
|
950
|
+
* Show detailed release information
|
|
951
|
+
*/
|
|
952
|
+
async function showReleaseDetails(release) {
|
|
953
|
+
console.log(
|
|
954
|
+
boxen(
|
|
955
|
+
chalk.bold.cyan(`v${release.version}\n`) +
|
|
956
|
+
chalk.dim(`Released: ${release.date}\n\n`) +
|
|
957
|
+
chalk.white(release.summary),
|
|
958
|
+
{
|
|
959
|
+
padding: 1,
|
|
960
|
+
borderStyle: 'round',
|
|
961
|
+
borderColor: 'cyan',
|
|
962
|
+
title: '📦 Release Details',
|
|
963
|
+
titleAlignment: 'center',
|
|
964
|
+
}
|
|
965
|
+
)
|
|
966
|
+
);
|
|
967
|
+
|
|
968
|
+
// Show highlights
|
|
969
|
+
if (release.highlights && release.highlights.length > 0) {
|
|
970
|
+
console.log(chalk.bold('\n✨ Highlights:\n'));
|
|
971
|
+
release.highlights.forEach((h) => {
|
|
972
|
+
console.log(` • ${h}`);
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
// Show new features
|
|
977
|
+
if (release.newFeatures) {
|
|
978
|
+
const { commands, agents, skills, hooks, other } = release.newFeatures;
|
|
979
|
+
|
|
980
|
+
if (commands && commands.length > 0) {
|
|
981
|
+
console.log(chalk.bold('\n📝 New Commands:\n'));
|
|
982
|
+
commands.forEach((cmd) => {
|
|
983
|
+
console.log(` ${chalk.cyan(`/${cmd.name}`)} - ${cmd.description}`);
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
if (agents && agents.length > 0) {
|
|
988
|
+
console.log(chalk.bold('\n🤖 New Agents:\n'));
|
|
989
|
+
agents.forEach((agent) => {
|
|
990
|
+
console.log(` ${chalk.cyan(agent.name)} - ${agent.description}`);
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
if (skills && skills.length > 0) {
|
|
995
|
+
console.log(chalk.bold('\n🎯 New Skills:\n'));
|
|
996
|
+
skills.forEach((skill) => {
|
|
997
|
+
console.log(` ${chalk.cyan(skill.name)} - ${skill.description}`);
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
if (hooks && hooks.length > 0) {
|
|
1002
|
+
console.log(chalk.bold('\n🪝 New Hooks:\n'));
|
|
1003
|
+
hooks.forEach((hook) => {
|
|
1004
|
+
console.log(` ${chalk.cyan(hook.name)} - ${hook.description}`);
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
if (other && other.length > 0) {
|
|
1009
|
+
console.log(chalk.bold('\n🔧 Other Improvements:\n'));
|
|
1010
|
+
other.forEach((item) => {
|
|
1011
|
+
console.log(` ${chalk.cyan(item.name)} - ${item.description}`);
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// Show breaking changes
|
|
1017
|
+
if (release.breaking && release.breaking.length > 0) {
|
|
1018
|
+
console.log(chalk.bold.red('\n⚠️ Breaking Changes:\n'));
|
|
1019
|
+
release.breaking.forEach((b) => {
|
|
1020
|
+
console.log(` ${chalk.red('!')} ${b}`);
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
console.log('');
|
|
1025
|
+
|
|
1026
|
+
// Offer to add features from this release
|
|
1027
|
+
const hasNewFeatures =
|
|
1028
|
+
release.newFeatures &&
|
|
1029
|
+
(release.newFeatures.commands?.length > 0 ||
|
|
1030
|
+
release.newFeatures.agents?.length > 0 ||
|
|
1031
|
+
release.newFeatures.skills?.length > 0 ||
|
|
1032
|
+
release.newFeatures.hooks?.length > 0);
|
|
1033
|
+
|
|
1034
|
+
if (hasNewFeatures) {
|
|
1035
|
+
const { addFeatures } = await inquirer.prompt([
|
|
1036
|
+
{
|
|
1037
|
+
type: 'confirm',
|
|
1038
|
+
name: 'addFeatures',
|
|
1039
|
+
message: 'Would you like to add features from this release to your project?',
|
|
1040
|
+
default: false,
|
|
1041
|
+
},
|
|
1042
|
+
]);
|
|
1043
|
+
|
|
1044
|
+
if (addFeatures) {
|
|
1045
|
+
await addFeaturesFromRelease(release);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
/**
|
|
1051
|
+
* Show menu to add available features
|
|
1052
|
+
*/
|
|
1053
|
+
async function showAddFeaturesMenu() {
|
|
1054
|
+
const claudeDir = join(process.cwd(), '.claude');
|
|
1055
|
+
const commandsDir = join(claudeDir, 'commands');
|
|
1056
|
+
|
|
1057
|
+
if (!existsSync(claudeDir)) {
|
|
1058
|
+
console.log(chalk.yellow('\n⚠️ No .claude folder found. Run Quick Start (1) or Full Setup (2) first.\n'));
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
// Get existing commands
|
|
1063
|
+
const existingCommands = existsSync(commandsDir)
|
|
1064
|
+
? readdirSync(commandsDir).filter((f) => f.endsWith('.md') && f !== 'INDEX.md' && f !== 'README.md').map((f) => f.replace('.md', ''))
|
|
1065
|
+
: [];
|
|
1066
|
+
|
|
1067
|
+
// Get all available features from releases
|
|
1068
|
+
const { releases, featureRegistry } = loadReleaseNotes();
|
|
1069
|
+
|
|
1070
|
+
if (!featureRegistry || !featureRegistry.commands) {
|
|
1071
|
+
console.log(chalk.yellow('\n No feature registry available.\n'));
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
// Find commands not yet installed
|
|
1076
|
+
const availableCommands = Object.entries(featureRegistry.commands)
|
|
1077
|
+
.filter(([name, info]) => !existingCommands.includes(name) && !info.required)
|
|
1078
|
+
.map(([name, info]) => {
|
|
1079
|
+
// Find description from releases
|
|
1080
|
+
let description = 'No description available';
|
|
1081
|
+
for (const release of releases) {
|
|
1082
|
+
const cmd = release.newFeatures?.commands?.find((c) => c.name === name);
|
|
1083
|
+
if (cmd) {
|
|
1084
|
+
description = cmd.description;
|
|
1085
|
+
break;
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
return { name, description, addedIn: info.addedIn };
|
|
1089
|
+
});
|
|
1090
|
+
|
|
1091
|
+
if (availableCommands.length === 0) {
|
|
1092
|
+
console.log(chalk.green('\n✓ All available commands are already installed!\n'));
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
console.log(chalk.bold('\n📦 Available Commands to Add:\n'));
|
|
1097
|
+
console.log(chalk.dim(' Select commands to add to your project:\n'));
|
|
1098
|
+
|
|
1099
|
+
const { selectedCommands } = await inquirer.prompt([
|
|
1100
|
+
{
|
|
1101
|
+
type: 'checkbox',
|
|
1102
|
+
name: 'selectedCommands',
|
|
1103
|
+
message: 'Select commands to install:',
|
|
1104
|
+
choices: availableCommands.map((cmd) => ({
|
|
1105
|
+
name: `/${cmd.name} - ${cmd.description} ${chalk.dim(`(v${cmd.addedIn})`)}`,
|
|
1106
|
+
value: cmd.name,
|
|
1107
|
+
checked: false,
|
|
1108
|
+
})),
|
|
1109
|
+
pageSize: 15,
|
|
1110
|
+
},
|
|
1111
|
+
]);
|
|
1112
|
+
|
|
1113
|
+
if (selectedCommands.length === 0) {
|
|
1114
|
+
console.log(chalk.dim('\n No commands selected.\n'));
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
// Install selected commands
|
|
1119
|
+
const spinner = ora('Installing commands...').start();
|
|
1120
|
+
const installed = [];
|
|
1121
|
+
const failed = [];
|
|
1122
|
+
|
|
1123
|
+
for (const cmdName of selectedCommands) {
|
|
1124
|
+
try {
|
|
1125
|
+
// Look for template file
|
|
1126
|
+
const templatePath = join(__dirname, '..', '..', 'templates', 'commands', `${cmdName}.template.md`);
|
|
1127
|
+
|
|
1128
|
+
if (existsSync(templatePath)) {
|
|
1129
|
+
const content = readFileSync(templatePath, 'utf8');
|
|
1130
|
+
const cmdPath = join(commandsDir, `${cmdName}.md`);
|
|
1131
|
+
writeFileSync(cmdPath, content, 'utf8');
|
|
1132
|
+
installed.push(cmdName);
|
|
1133
|
+
markFeatureInstalled(cmdName);
|
|
1134
|
+
} else {
|
|
1135
|
+
failed.push({ name: cmdName, error: 'Template not found' });
|
|
1136
|
+
}
|
|
1137
|
+
} catch (error) {
|
|
1138
|
+
failed.push({ name: cmdName, error: error.message });
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
spinner.stop();
|
|
1143
|
+
|
|
1144
|
+
if (installed.length > 0) {
|
|
1145
|
+
console.log(chalk.green(`\n✓ Installed ${installed.length} command(s):`));
|
|
1146
|
+
installed.forEach((cmd) => {
|
|
1147
|
+
console.log(` ${chalk.cyan(`/${cmd}`)}`);
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
if (failed.length > 0) {
|
|
1152
|
+
console.log(chalk.red(`\n✗ Failed to install ${failed.length} command(s):`));
|
|
1153
|
+
failed.forEach((f) => {
|
|
1154
|
+
console.log(` ${chalk.red(`/${f.name}`)}: ${f.error}`);
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
if (installed.length > 0) {
|
|
1159
|
+
showRestartReminder();
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
/**
|
|
1164
|
+
* Add features from a specific release
|
|
1165
|
+
*/
|
|
1166
|
+
async function addFeaturesFromRelease(release) {
|
|
1167
|
+
const claudeDir = join(process.cwd(), '.claude');
|
|
1168
|
+
const commandsDir = join(claudeDir, 'commands');
|
|
1169
|
+
|
|
1170
|
+
if (!existsSync(claudeDir)) {
|
|
1171
|
+
console.log(chalk.yellow('\n⚠️ No .claude folder found. Run Quick Start (1) or Full Setup (2) first.\n'));
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
if (!release.newFeatures?.commands || release.newFeatures.commands.length === 0) {
|
|
1176
|
+
console.log(chalk.yellow('\n No commands to add from this release.\n'));
|
|
1177
|
+
return;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
// Get existing commands
|
|
1181
|
+
const existingCommands = existsSync(commandsDir)
|
|
1182
|
+
? readdirSync(commandsDir).filter((f) => f.endsWith('.md')).map((f) => f.replace('.md', ''))
|
|
1183
|
+
: [];
|
|
1184
|
+
|
|
1185
|
+
// Filter to commands not yet installed
|
|
1186
|
+
const availableCommands = release.newFeatures.commands.filter((cmd) => !existingCommands.includes(cmd.name));
|
|
1187
|
+
|
|
1188
|
+
if (availableCommands.length === 0) {
|
|
1189
|
+
console.log(chalk.green('\n✓ All commands from this release are already installed!\n'));
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
const { selectedCommands } = await inquirer.prompt([
|
|
1194
|
+
{
|
|
1195
|
+
type: 'checkbox',
|
|
1196
|
+
name: 'selectedCommands',
|
|
1197
|
+
message: 'Select commands to install:',
|
|
1198
|
+
choices: availableCommands.map((cmd) => ({
|
|
1199
|
+
name: `/${cmd.name} - ${cmd.description}`,
|
|
1200
|
+
value: cmd.name,
|
|
1201
|
+
checked: true,
|
|
1202
|
+
})),
|
|
1203
|
+
pageSize: 10,
|
|
1204
|
+
},
|
|
1205
|
+
]);
|
|
1206
|
+
|
|
1207
|
+
if (selectedCommands.length === 0) {
|
|
1208
|
+
console.log(chalk.dim('\n No commands selected.\n'));
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
// Install selected commands
|
|
1213
|
+
const spinner = ora('Installing commands...').start();
|
|
1214
|
+
const installed = [];
|
|
1215
|
+
const failed = [];
|
|
1216
|
+
|
|
1217
|
+
for (const cmdName of selectedCommands) {
|
|
1218
|
+
try {
|
|
1219
|
+
const templatePath = join(__dirname, '..', '..', 'templates', 'commands', `${cmdName}.template.md`);
|
|
1220
|
+
|
|
1221
|
+
if (existsSync(templatePath)) {
|
|
1222
|
+
const content = readFileSync(templatePath, 'utf8');
|
|
1223
|
+
const cmdPath = join(commandsDir, `${cmdName}.md`);
|
|
1224
|
+
writeFileSync(cmdPath, content, 'utf8');
|
|
1225
|
+
installed.push(cmdName);
|
|
1226
|
+
markFeatureInstalled(cmdName);
|
|
1227
|
+
} else {
|
|
1228
|
+
failed.push({ name: cmdName, error: 'Template not found' });
|
|
1229
|
+
}
|
|
1230
|
+
} catch (error) {
|
|
1231
|
+
failed.push({ name: cmdName, error: error.message });
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
spinner.stop();
|
|
1236
|
+
|
|
1237
|
+
if (installed.length > 0) {
|
|
1238
|
+
console.log(chalk.green(`\n✓ Installed ${installed.length} command(s):`));
|
|
1239
|
+
installed.forEach((cmd) => {
|
|
1240
|
+
console.log(` ${chalk.cyan(`/${cmd}`)}`);
|
|
1241
|
+
});
|
|
1242
|
+
showRestartReminder();
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
if (failed.length > 0) {
|
|
1246
|
+
console.log(chalk.red(`\n✗ Failed to install ${failed.length} command(s):`));
|
|
1247
|
+
failed.forEach((f) => {
|
|
1248
|
+
console.log(` ${chalk.red(`/${f.name}`)}: ${f.error}`);
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
/**
|
|
1254
|
+
* Check for updates and show banner if available
|
|
1255
|
+
*/
|
|
1256
|
+
async function checkAndShowUpdateBanner() {
|
|
1257
|
+
try {
|
|
1258
|
+
const checkResult = await performVersionCheck(process.cwd(), false);
|
|
1259
|
+
|
|
1260
|
+
if (checkResult.updateAvailable && checkResult.shouldNotify) {
|
|
1261
|
+
const banner = formatUpdateBanner(checkResult);
|
|
1262
|
+
if (banner) {
|
|
1263
|
+
console.log(chalk.yellow(banner));
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
return checkResult;
|
|
1268
|
+
} catch {
|
|
1269
|
+
// Silently fail - network might be unavailable
|
|
1270
|
+
return null;
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
|
|
621
1274
|
/**
|
|
622
1275
|
* Main setup wizard - entry point
|
|
623
1276
|
*/
|
|
624
1277
|
export async function runSetupWizard(options = {}) {
|
|
625
1278
|
showSetupHeader();
|
|
626
1279
|
|
|
1280
|
+
// Check for updates in background (non-blocking display)
|
|
1281
|
+
await checkAndShowUpdateBanner();
|
|
1282
|
+
|
|
627
1283
|
// Check if .claude already exists
|
|
628
1284
|
const claudeDir = join(process.cwd(), '.claude');
|
|
629
1285
|
const claudeMd = join(process.cwd(), 'CLAUDE.md');
|
|
@@ -644,7 +1300,7 @@ export async function runSetupWizard(options = {}) {
|
|
|
644
1300
|
name: 'action',
|
|
645
1301
|
message: 'What would you like to do?',
|
|
646
1302
|
choices: SETUP_OPTIONS,
|
|
647
|
-
pageSize:
|
|
1303
|
+
pageSize: 12,
|
|
648
1304
|
},
|
|
649
1305
|
]);
|
|
650
1306
|
|
|
@@ -666,44 +1322,12 @@ export async function runSetupWizard(options = {}) {
|
|
|
666
1322
|
showRestartReminder();
|
|
667
1323
|
break;
|
|
668
1324
|
|
|
669
|
-
case 'audit':
|
|
670
|
-
await runClaudeAudit();
|
|
671
|
-
// Audit doesn't modify files, no restart needed
|
|
672
|
-
break;
|
|
673
|
-
|
|
674
|
-
case 'enhance':
|
|
675
|
-
await runEnhancement();
|
|
676
|
-
// Enhancement modifies CLAUDE.md which requires restart
|
|
677
|
-
showRestartReminder();
|
|
678
|
-
break;
|
|
679
|
-
|
|
680
|
-
case 'detect':
|
|
681
|
-
const spinner = ora('Detecting tech stack...').start();
|
|
682
|
-
try {
|
|
683
|
-
const techStack = await detectTechStack(process.cwd());
|
|
684
|
-
spinner.succeed('Detection complete!');
|
|
685
|
-
console.log(chalk.bold('\nDetected Tech Stack:'));
|
|
686
|
-
console.log(JSON.stringify(techStack, null, 2));
|
|
687
|
-
} catch (error) {
|
|
688
|
-
spinner.fail('Detection failed');
|
|
689
|
-
console.error(chalk.red(error.message));
|
|
690
|
-
}
|
|
691
|
-
console.log('');
|
|
692
|
-
break;
|
|
693
|
-
|
|
694
1325
|
case 'templates':
|
|
695
1326
|
await showTemplates();
|
|
696
1327
|
break;
|
|
697
1328
|
|
|
698
|
-
case '
|
|
699
|
-
|
|
700
|
-
if (!existsSync(join(process.cwd(), '.claude'))) {
|
|
701
|
-
console.log(chalk.yellow('\n⚠️ No .claude folder found. Run Quick Start (1) or Full Setup (2) first.\n'));
|
|
702
|
-
} else {
|
|
703
|
-
await showProjectSettingsMenu();
|
|
704
|
-
// Settings modify tech-stack.json which may require restart
|
|
705
|
-
showRestartReminder();
|
|
706
|
-
}
|
|
1329
|
+
case 'releases':
|
|
1330
|
+
await showPriorReleases();
|
|
707
1331
|
break;
|
|
708
1332
|
|
|
709
1333
|
case 'remove':
|
|
@@ -733,8 +1357,6 @@ Run the Claude CLI Advanced Starter Pack setup wizard.
|
|
|
733
1357
|
|
|
734
1358
|
This command launches the interactive setup wizard for configuring:
|
|
735
1359
|
- .claude folder structure
|
|
736
|
-
- CLAUDE.md generation
|
|
737
|
-
- Tech stack detection
|
|
738
1360
|
- GitHub project integration
|
|
739
1361
|
- Agents, hooks, and skills
|
|
740
1362
|
|
|
@@ -744,10 +1366,14 @@ Reply with a number to jump to that option:
|
|
|
744
1366
|
1. Quick Start - Auto-detect and initialize
|
|
745
1367
|
2. Full Setup - All features with customization
|
|
746
1368
|
3. GitHub Setup - Connect to project board
|
|
747
|
-
4.
|
|
748
|
-
5.
|
|
749
|
-
6.
|
|
750
|
-
|
|
1369
|
+
4. View Templates - Browse available templates
|
|
1370
|
+
5. Prior Releases - Review & add features from past versions
|
|
1371
|
+
6. Remove CCASP - Uninstall from this project
|
|
1372
|
+
|
|
1373
|
+
## Related Commands
|
|
1374
|
+
|
|
1375
|
+
- \`/project-impl\` - Agent-powered project implementation (audit, enhance, detect, configure)
|
|
1376
|
+
- \`/update-check\` - Check for updates and add new features
|
|
751
1377
|
|
|
752
1378
|
## From Terminal
|
|
753
1379
|
|