claude-cli-advanced-starter-pack 1.8.5 → 1.8.6
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/package.json +1 -1
- package/src/cli/menu.js +1 -1
- package/src/commands/explore-mcp/claude-md-updater.js +38 -3
- package/src/commands/init.js +89 -0
- package/src/commands/setup-wizard.js +85 -30
- package/src/data/releases.json +15 -0
- package/src/utils/version-check.js +43 -17
- package/templates/commands/create-task-list-for-issue.template.md +72 -0
- package/templates/commands/create-task-list.template.md +73 -0
- package/templates/commands/detect-tech-stack.template.md +137 -0
- package/templates/commands/menu-issues-list.template.md +72 -0
- package/templates/hooks/ccasp-update-check.template.js +36 -1
package/package.json
CHANGED
package/src/cli/menu.js
CHANGED
|
@@ -7,8 +7,33 @@
|
|
|
7
7
|
|
|
8
8
|
import chalk from 'chalk';
|
|
9
9
|
import ora from 'ora';
|
|
10
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
11
|
-
import { join } from 'path';
|
|
10
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from 'fs';
|
|
11
|
+
import { join, basename } from 'path';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create a backup of CLAUDE.md before modification
|
|
15
|
+
* @param {string} filePath - Path to CLAUDE.md
|
|
16
|
+
* @param {string} cwd - Working directory
|
|
17
|
+
* @returns {string|null} Backup path or null if failed
|
|
18
|
+
*/
|
|
19
|
+
function backupClaudeMd(filePath, cwd) {
|
|
20
|
+
if (!existsSync(filePath)) return null;
|
|
21
|
+
|
|
22
|
+
const backupDir = join(cwd, '.claude', 'backups');
|
|
23
|
+
if (!existsSync(backupDir)) {
|
|
24
|
+
mkdirSync(backupDir, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
28
|
+
const backupPath = join(backupDir, `CLAUDE.md.${timestamp}.bak`);
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
copyFileSync(filePath, backupPath);
|
|
32
|
+
return backupPath;
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
12
37
|
|
|
13
38
|
/**
|
|
14
39
|
* MCP section marker
|
|
@@ -158,6 +183,12 @@ ${mcpSection}
|
|
|
158
183
|
};
|
|
159
184
|
}
|
|
160
185
|
|
|
186
|
+
// Backup existing CLAUDE.md before modification
|
|
187
|
+
const backupPath = backupClaudeMd(claudeMdPath, cwd);
|
|
188
|
+
if (backupPath) {
|
|
189
|
+
spinner.text = 'Backed up CLAUDE.md...';
|
|
190
|
+
}
|
|
191
|
+
|
|
161
192
|
// Check if MCP section exists
|
|
162
193
|
const hasStartMarker = content.includes(MCP_SECTION_START);
|
|
163
194
|
const hasEndMarker = content.includes(MCP_SECTION_END);
|
|
@@ -193,12 +224,13 @@ ${mcpSection}
|
|
|
193
224
|
}
|
|
194
225
|
|
|
195
226
|
writeFileSync(claudeMdPath, content, 'utf8');
|
|
196
|
-
spinner.succeed(
|
|
227
|
+
spinner.succeed(`Updated CLAUDE.md with MCP documentation${backupPath ? ' (backup created)' : ''}`);
|
|
197
228
|
|
|
198
229
|
return {
|
|
199
230
|
success: true,
|
|
200
231
|
action: hasStartMarker ? 'updated' : 'appended',
|
|
201
232
|
path: claudeMdPath,
|
|
233
|
+
backupPath: backupPath || null,
|
|
202
234
|
};
|
|
203
235
|
} catch (error) {
|
|
204
236
|
spinner.fail(`Failed to update CLAUDE.md: ${error.message}`);
|
|
@@ -225,6 +257,9 @@ export function removeMcpSection(cwd = process.cwd()) {
|
|
|
225
257
|
const hasEndMarker = content.includes(MCP_SECTION_END);
|
|
226
258
|
|
|
227
259
|
if (hasStartMarker && hasEndMarker) {
|
|
260
|
+
// Backup before removal
|
|
261
|
+
backupClaudeMd(claudeMdPath, cwd);
|
|
262
|
+
|
|
228
263
|
const regex = new RegExp(
|
|
229
264
|
`\\n?${MCP_SECTION_START}[\\s\\S]*?${MCP_SECTION_END}\\n?`,
|
|
230
265
|
'g'
|
package/src/commands/init.js
CHANGED
|
@@ -219,6 +219,12 @@ const AVAILABLE_COMMANDS = [
|
|
|
219
219
|
category: 'Claude Code',
|
|
220
220
|
selected: true,
|
|
221
221
|
},
|
|
222
|
+
{
|
|
223
|
+
name: 'detect-tech-stack',
|
|
224
|
+
description: 'Re-run tech stack detection and update configuration',
|
|
225
|
+
category: 'Analysis',
|
|
226
|
+
selected: true,
|
|
227
|
+
},
|
|
222
228
|
{
|
|
223
229
|
name: 'roadmap-sync',
|
|
224
230
|
description: 'Sync roadmaps with GitHub Project Board',
|
|
@@ -2795,3 +2801,86 @@ npx claude-cli-advanced-starter-pack init --force
|
|
|
2795
2801
|
|
|
2796
2802
|
return content;
|
|
2797
2803
|
}
|
|
2804
|
+
|
|
2805
|
+
/**
|
|
2806
|
+
* Verify and fix legacy installations (pre-v1.0.8)
|
|
2807
|
+
* Issue #8: Ensures update-check hook is properly configured
|
|
2808
|
+
*
|
|
2809
|
+
* @param {string} projectDir - Project directory to verify
|
|
2810
|
+
* @returns {Object} Verification result with fixes applied
|
|
2811
|
+
*/
|
|
2812
|
+
export async function verifyLegacyInstallation(projectDir = process.cwd()) {
|
|
2813
|
+
const fixes = [];
|
|
2814
|
+
const issues = [];
|
|
2815
|
+
|
|
2816
|
+
const claudeDir = join(projectDir, '.claude');
|
|
2817
|
+
const hooksDir = join(claudeDir, 'hooks');
|
|
2818
|
+
const settingsPath = join(claudeDir, 'settings.json');
|
|
2819
|
+
const updateCheckHookPath = join(hooksDir, 'ccasp-update-check.js');
|
|
2820
|
+
|
|
2821
|
+
// Check if this is a CCASP installation
|
|
2822
|
+
if (!existsSync(claudeDir)) {
|
|
2823
|
+
return { isLegacy: false, message: 'No .claude folder found' };
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
// Check 1: Does the update-check hook file exist?
|
|
2827
|
+
if (!existsSync(updateCheckHookPath)) {
|
|
2828
|
+
issues.push('Missing ccasp-update-check.js hook file');
|
|
2829
|
+
|
|
2830
|
+
// Fix: Create the hook file
|
|
2831
|
+
if (!existsSync(hooksDir)) {
|
|
2832
|
+
mkdirSync(hooksDir, { recursive: true });
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
const templatePath = join(__dirname, '..', '..', 'templates', 'hooks', 'ccasp-update-check.template.js');
|
|
2836
|
+
if (existsSync(templatePath)) {
|
|
2837
|
+
const hookContent = readFileSync(templatePath, 'utf8');
|
|
2838
|
+
writeFileSync(updateCheckHookPath, hookContent, 'utf8');
|
|
2839
|
+
fixes.push('Created ccasp-update-check.js hook file');
|
|
2840
|
+
}
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
// Check 2: Is the hook registered in settings.json?
|
|
2844
|
+
if (existsSync(settingsPath)) {
|
|
2845
|
+
try {
|
|
2846
|
+
const settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
2847
|
+
|
|
2848
|
+
// Check if UserPromptSubmit hook exists with update-check
|
|
2849
|
+
const hasUpdateHook = settings.hooks?.UserPromptSubmit?.some(
|
|
2850
|
+
(h) => h.hooks?.some((hook) => hook.command?.includes('ccasp-update-check'))
|
|
2851
|
+
);
|
|
2852
|
+
|
|
2853
|
+
if (!hasUpdateHook) {
|
|
2854
|
+
issues.push('Update-check hook not registered in settings.json');
|
|
2855
|
+
|
|
2856
|
+
// Fix: Add the hook to settings.json
|
|
2857
|
+
if (!settings.hooks) settings.hooks = {};
|
|
2858
|
+
if (!settings.hooks.UserPromptSubmit) {
|
|
2859
|
+
settings.hooks.UserPromptSubmit = [];
|
|
2860
|
+
}
|
|
2861
|
+
|
|
2862
|
+
settings.hooks.UserPromptSubmit.push({
|
|
2863
|
+
matcher: '',
|
|
2864
|
+
hooks: [{
|
|
2865
|
+
type: 'command',
|
|
2866
|
+
command: 'node .claude/hooks/ccasp-update-check.js',
|
|
2867
|
+
}],
|
|
2868
|
+
});
|
|
2869
|
+
|
|
2870
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
|
2871
|
+
fixes.push('Registered update-check hook in settings.json');
|
|
2872
|
+
}
|
|
2873
|
+
} catch {
|
|
2874
|
+
issues.push('Could not parse settings.json');
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
|
|
2878
|
+
return {
|
|
2879
|
+
isLegacy: issues.length > 0,
|
|
2880
|
+
issues,
|
|
2881
|
+
fixes,
|
|
2882
|
+
message: fixes.length > 0
|
|
2883
|
+
? `Fixed ${fixes.length} legacy installation issue(s)`
|
|
2884
|
+
: 'Installation is up to date',
|
|
2885
|
+
};
|
|
2886
|
+
}
|
|
@@ -578,43 +578,60 @@ function showSetupHeader() {
|
|
|
578
578
|
}
|
|
579
579
|
|
|
580
580
|
/**
|
|
581
|
-
*
|
|
581
|
+
* Streamlined setup options - 3 core paths for easy mobile input
|
|
582
|
+
* Issue #8: Simplified from 7 options to reduce scrolling
|
|
582
583
|
*/
|
|
583
584
|
const SETUP_OPTIONS = [
|
|
584
585
|
{
|
|
585
|
-
name: `${chalk.
|
|
586
|
-
value: '
|
|
587
|
-
short: '
|
|
586
|
+
name: `${chalk.green('1.')} Auto Install ${chalk.dim('- Full features + backup (recommended)')}`,
|
|
587
|
+
value: 'auto',
|
|
588
|
+
short: 'Auto Install',
|
|
588
589
|
},
|
|
589
590
|
{
|
|
590
|
-
name: `${chalk.yellow('2.')}
|
|
591
|
-
value: 'full',
|
|
592
|
-
short: 'Full Setup',
|
|
593
|
-
},
|
|
594
|
-
{
|
|
595
|
-
name: `${chalk.yellow('3.')} GitHub Setup ${chalk.dim('- Connect project board')}`,
|
|
591
|
+
name: `${chalk.yellow('2.')} GitHub Setup ${chalk.dim('- Connect project board')}`,
|
|
596
592
|
value: 'github',
|
|
597
593
|
short: 'GitHub',
|
|
598
594
|
},
|
|
599
595
|
{
|
|
600
|
-
name: `${chalk.
|
|
596
|
+
name: `${chalk.dim('3.')} More Options ${chalk.dim('- Templates, releases, remove')}`,
|
|
597
|
+
value: 'more',
|
|
598
|
+
short: 'More',
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
name: `${chalk.dim('0.')} Exit`,
|
|
602
|
+
value: 'exit',
|
|
603
|
+
short: 'Exit',
|
|
604
|
+
},
|
|
605
|
+
];
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Advanced options submenu - accessed via "More Options"
|
|
609
|
+
*/
|
|
610
|
+
const ADVANCED_OPTIONS = [
|
|
611
|
+
{
|
|
612
|
+
name: `${chalk.yellow('1.')} Custom Setup ${chalk.dim('- Choose specific features')}`,
|
|
613
|
+
value: 'custom',
|
|
614
|
+
short: 'Custom',
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
name: `${chalk.yellow('2.')} View Templates ${chalk.dim('- Browse available items')}`,
|
|
601
618
|
value: 'templates',
|
|
602
619
|
short: 'Templates',
|
|
603
620
|
},
|
|
604
621
|
{
|
|
605
|
-
name: `${chalk.yellow('
|
|
622
|
+
name: `${chalk.yellow('3.')} Prior Releases ${chalk.dim('- Add features from past versions')}`,
|
|
606
623
|
value: 'releases',
|
|
607
624
|
short: 'Releases',
|
|
608
625
|
},
|
|
609
626
|
{
|
|
610
|
-
name: `${chalk.yellow('
|
|
627
|
+
name: `${chalk.yellow('4.')} Remove CCASP ${chalk.dim('- Uninstall from this project')}`,
|
|
611
628
|
value: 'remove',
|
|
612
629
|
short: 'Remove',
|
|
613
630
|
},
|
|
614
631
|
{
|
|
615
|
-
name: `${chalk.
|
|
616
|
-
value: '
|
|
617
|
-
short: '
|
|
632
|
+
name: `${chalk.dim('0.')} Back`,
|
|
633
|
+
value: 'back',
|
|
634
|
+
short: 'Back',
|
|
618
635
|
},
|
|
619
636
|
];
|
|
620
637
|
|
|
@@ -1292,7 +1309,7 @@ export async function runSetupWizard(options = {}) {
|
|
|
1292
1309
|
console.log(chalk.green('✓ CLAUDE.md exists\n'));
|
|
1293
1310
|
}
|
|
1294
1311
|
|
|
1295
|
-
// Main menu loop
|
|
1312
|
+
// Main menu loop - streamlined 3-path flow (Issue #8)
|
|
1296
1313
|
let running = true;
|
|
1297
1314
|
while (running) {
|
|
1298
1315
|
const { action } = await inquirer.prompt([
|
|
@@ -1301,28 +1318,67 @@ export async function runSetupWizard(options = {}) {
|
|
|
1301
1318
|
name: 'action',
|
|
1302
1319
|
message: 'What would you like to do?',
|
|
1303
1320
|
choices: SETUP_OPTIONS,
|
|
1304
|
-
pageSize:
|
|
1321
|
+
pageSize: 6, // All options visible without scrolling
|
|
1305
1322
|
},
|
|
1306
1323
|
]);
|
|
1307
1324
|
|
|
1308
1325
|
switch (action) {
|
|
1309
|
-
case '
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1326
|
+
case 'auto':
|
|
1327
|
+
// Auto Install: Full features with mandatory backup (Issue #8 requirement)
|
|
1328
|
+
console.log(chalk.cyan('\n📦 Auto Install Mode - Full features with backup\n'));
|
|
1329
|
+
await runInit({
|
|
1330
|
+
interactive: false,
|
|
1331
|
+
backup: true, // Mandatory backup
|
|
1332
|
+
force: true, // Overwrite enabled for testing phase
|
|
1333
|
+
skipPrompts: true,
|
|
1334
|
+
preset: 'full' // All features
|
|
1335
|
+
});
|
|
1316
1336
|
showRestartReminder();
|
|
1317
1337
|
running = false;
|
|
1318
1338
|
break;
|
|
1319
1339
|
|
|
1320
1340
|
case 'github':
|
|
1321
1341
|
await runGitHubSetup({});
|
|
1322
|
-
// GitHub setup modifies .claude/ config
|
|
1323
1342
|
showRestartReminder();
|
|
1324
1343
|
break;
|
|
1325
1344
|
|
|
1345
|
+
case 'more':
|
|
1346
|
+
// Advanced options submenu
|
|
1347
|
+
await showAdvancedOptions();
|
|
1348
|
+
break;
|
|
1349
|
+
|
|
1350
|
+
case 'exit':
|
|
1351
|
+
running = false;
|
|
1352
|
+
console.log(chalk.dim('\nRun `ccasp wizard` anytime to return.\n'));
|
|
1353
|
+
break;
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
/**
|
|
1359
|
+
* Advanced options submenu - Issue #8: Moved less-used options here
|
|
1360
|
+
*/
|
|
1361
|
+
async function showAdvancedOptions() {
|
|
1362
|
+
let inSubmenu = true;
|
|
1363
|
+
|
|
1364
|
+
while (inSubmenu) {
|
|
1365
|
+
const { action } = await inquirer.prompt([
|
|
1366
|
+
{
|
|
1367
|
+
type: 'list',
|
|
1368
|
+
name: 'action',
|
|
1369
|
+
message: 'Advanced Options:',
|
|
1370
|
+
choices: ADVANCED_OPTIONS,
|
|
1371
|
+
pageSize: 6,
|
|
1372
|
+
},
|
|
1373
|
+
]);
|
|
1374
|
+
|
|
1375
|
+
switch (action) {
|
|
1376
|
+
case 'custom':
|
|
1377
|
+
await runInit({ interactive: true });
|
|
1378
|
+
showRestartReminder();
|
|
1379
|
+
inSubmenu = false;
|
|
1380
|
+
break;
|
|
1381
|
+
|
|
1326
1382
|
case 'templates':
|
|
1327
1383
|
await showTemplates();
|
|
1328
1384
|
break;
|
|
@@ -1334,13 +1390,12 @@ export async function runSetupWizard(options = {}) {
|
|
|
1334
1390
|
case 'remove':
|
|
1335
1391
|
const removed = await runRemove();
|
|
1336
1392
|
if (removed) {
|
|
1337
|
-
|
|
1393
|
+
inSubmenu = false;
|
|
1338
1394
|
}
|
|
1339
1395
|
break;
|
|
1340
1396
|
|
|
1341
|
-
case '
|
|
1342
|
-
|
|
1343
|
-
console.log(chalk.dim('\nRun `ccasp wizard` anytime to return.\n'));
|
|
1397
|
+
case 'back':
|
|
1398
|
+
inSubmenu = false;
|
|
1344
1399
|
break;
|
|
1345
1400
|
}
|
|
1346
1401
|
}
|
package/src/data/releases.json
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"releases": [
|
|
3
|
+
{
|
|
4
|
+
"version": "1.8.6",
|
|
5
|
+
"date": "2026-01-31",
|
|
6
|
+
"summary": "Release notes pending",
|
|
7
|
+
"highlights": [],
|
|
8
|
+
"newFeatures": {
|
|
9
|
+
"commands": [],
|
|
10
|
+
"agents": [],
|
|
11
|
+
"skills": [],
|
|
12
|
+
"hooks": [],
|
|
13
|
+
"other": []
|
|
14
|
+
},
|
|
15
|
+
"breaking": [],
|
|
16
|
+
"deprecated": []
|
|
17
|
+
},
|
|
3
18
|
{
|
|
4
19
|
"version": "1.8.5",
|
|
5
20
|
"date": "2026-01-31",
|
|
@@ -19,8 +19,9 @@ const PACKAGE_NAME = 'claude-cli-advanced-starter-pack';
|
|
|
19
19
|
// Cache duration: 1 hour (in milliseconds)
|
|
20
20
|
const CACHE_DURATION = 60 * 60 * 1000;
|
|
21
21
|
|
|
22
|
-
// Update notification
|
|
23
|
-
|
|
22
|
+
// Update notification reminder: Show reminder again after 7 days
|
|
23
|
+
// Issue #8: Changed from 1-day suppression to 7-day reminder
|
|
24
|
+
const UPDATE_NOTIFICATION_REMINDER = 7 * 24 * 60 * 60 * 1000;
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* Get the current installed version from package.json
|
|
@@ -313,19 +314,52 @@ export function compareVersions(v1, v2) {
|
|
|
313
314
|
/**
|
|
314
315
|
* Check npm registry for the latest version
|
|
315
316
|
* Returns null if check fails (network error, etc.)
|
|
317
|
+
* Issue #8: Added npm registry API fallback for Windows compatibility
|
|
316
318
|
*/
|
|
317
319
|
export async function checkLatestVersion() {
|
|
320
|
+
// Try npm CLI first
|
|
318
321
|
try {
|
|
319
|
-
// Use npm view command to get latest version
|
|
320
322
|
const result = execSync(`npm view ${PACKAGE_NAME} version`, {
|
|
321
323
|
encoding: 'utf8',
|
|
322
|
-
timeout: 10000,
|
|
324
|
+
timeout: 10000,
|
|
323
325
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
324
326
|
});
|
|
325
327
|
|
|
326
|
-
|
|
328
|
+
const version = result.trim();
|
|
329
|
+
if (version && /^\d+\.\d+\.\d+/.test(version)) {
|
|
330
|
+
return version;
|
|
331
|
+
}
|
|
332
|
+
} catch {
|
|
333
|
+
// npm CLI failed, try fallback
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Fallback: Direct npm registry API call (Issue #8 fix)
|
|
337
|
+
try {
|
|
338
|
+
const https = await import('https');
|
|
339
|
+
return new Promise((resolve) => {
|
|
340
|
+
const req = https.default.get(
|
|
341
|
+
`https://registry.npmjs.org/${PACKAGE_NAME}/latest`,
|
|
342
|
+
{ timeout: 8000 },
|
|
343
|
+
(res) => {
|
|
344
|
+
let data = '';
|
|
345
|
+
res.on('data', (chunk) => (data += chunk));
|
|
346
|
+
res.on('end', () => {
|
|
347
|
+
try {
|
|
348
|
+
const pkg = JSON.parse(data);
|
|
349
|
+
resolve(pkg.version || null);
|
|
350
|
+
} catch {
|
|
351
|
+
resolve(null);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
);
|
|
356
|
+
req.on('error', () => resolve(null));
|
|
357
|
+
req.on('timeout', () => {
|
|
358
|
+
req.destroy();
|
|
359
|
+
resolve(null);
|
|
360
|
+
});
|
|
361
|
+
});
|
|
327
362
|
} catch {
|
|
328
|
-
// Silently fail - network might be unavailable
|
|
329
363
|
return null;
|
|
330
364
|
}
|
|
331
365
|
}
|
|
@@ -436,17 +470,9 @@ export function shouldShowUpdateNotification(state, latestVersion) {
|
|
|
436
470
|
return false;
|
|
437
471
|
}
|
|
438
472
|
|
|
439
|
-
//
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
// If check is more than 1 day old, don't show notification
|
|
444
|
-
// (user needs to run check again to see new updates)
|
|
445
|
-
if (timeSinceCheck > UPDATE_NOTIFICATION_DURATION) {
|
|
446
|
-
return false;
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
473
|
+
// Issue #8: Always show notification if update is available
|
|
474
|
+
// The old logic suppressed notifications after 1 day, which was counterproductive
|
|
475
|
+
// Now we always show if there's an update, regardless of cache age
|
|
450
476
|
return true;
|
|
451
477
|
}
|
|
452
478
|
|
|
@@ -197,6 +197,78 @@ gh issue edit [NUMBER] --body "$(gh issue view [NUMBER] --json body -q .body)
|
|
|
197
197
|
|
|
198
198
|
---
|
|
199
199
|
|
|
200
|
+
### Step 7: After Task Completion - Close Issue Prompt
|
|
201
|
+
|
|
202
|
+
**CRITICAL: After ALL TodoWrite tasks are marked complete AND a commit is created, ALWAYS offer to close the issue.**
|
|
203
|
+
|
|
204
|
+
This step triggers when:
|
|
205
|
+
1. All tasks in TodoWrite are marked `completed`
|
|
206
|
+
2. A git commit has been made with changes
|
|
207
|
+
|
|
208
|
+
Display completion summary:
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
212
|
+
║ ✅ All Tasks Completed ║
|
|
213
|
+
╠═══════════════════════════════════════════════════════════════╣
|
|
214
|
+
║ ║
|
|
215
|
+
║ Issue: #[NUMBER] - [TITLE] ║
|
|
216
|
+
║ Commit: [SHORT_SHA] - [COMMIT_MSG_FIRST_LINE] ║
|
|
217
|
+
║ Tasks: [X] completed ║
|
|
218
|
+
║ ║
|
|
219
|
+
╠═══════════════════════════════════════════════════════════════╣
|
|
220
|
+
║ [C] Close issue with comment ║
|
|
221
|
+
║ [P] Push to origin + close issue ║
|
|
222
|
+
║ [K] Keep issue open ║
|
|
223
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Then ask:
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
header: "Issue"
|
|
230
|
+
question: "All tasks complete. Close issue #[NUMBER]?"
|
|
231
|
+
options:
|
|
232
|
+
- label: "C - Close with comment"
|
|
233
|
+
description: "Add completion summary and close"
|
|
234
|
+
- label: "P - Push + Close"
|
|
235
|
+
description: "Push commit to origin, then close"
|
|
236
|
+
- label: "K - Keep open"
|
|
237
|
+
description: "Leave issue open for follow-up"
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Handle Close Actions:**
|
|
241
|
+
|
|
242
|
+
**C (Close with comment):**
|
|
243
|
+
```bash
|
|
244
|
+
gh issue close [NUMBER] --comment "All tasks completed in commit [SHA].
|
|
245
|
+
|
|
246
|
+
## Completed Tasks
|
|
247
|
+
- ✅ Task 1
|
|
248
|
+
- ✅ Task 2
|
|
249
|
+
...
|
|
250
|
+
|
|
251
|
+
Ready for release."
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**P (Push + Close):**
|
|
255
|
+
```bash
|
|
256
|
+
git push origin HEAD
|
|
257
|
+
gh issue close [NUMBER] --comment "All tasks completed and pushed in commit [SHA].
|
|
258
|
+
|
|
259
|
+
## Completed Tasks
|
|
260
|
+
- ✅ Task 1
|
|
261
|
+
- ✅ Task 2
|
|
262
|
+
...
|
|
263
|
+
|
|
264
|
+
Ready for release."
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**K (Keep open):**
|
|
268
|
+
Display: "Issue #[NUMBER] kept open for follow-up."
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
200
272
|
## ERROR HANDLING
|
|
201
273
|
|
|
202
274
|
| Error | Action |
|
|
@@ -874,6 +874,79 @@ After all tasks are complete, display a summary:
|
|
|
874
874
|
|
|
875
875
|
---
|
|
876
876
|
|
|
877
|
+
## CLOSE ISSUE PROMPT (When Working From GitHub Issue)
|
|
878
|
+
|
|
879
|
+
**CRITICAL: If this task list was created for a GitHub issue, ALWAYS offer to close the issue after ALL TodoWrite tasks are marked complete AND a commit is created.**
|
|
880
|
+
|
|
881
|
+
This step triggers when:
|
|
882
|
+
1. The task list originated from a GitHub issue (via `/create-task-list for issue #N` or `/menu-issues-list`)
|
|
883
|
+
2. All tasks in TodoWrite are marked `completed`
|
|
884
|
+
3. A git commit has been made with changes
|
|
885
|
+
|
|
886
|
+
Display completion summary:
|
|
887
|
+
|
|
888
|
+
```
|
|
889
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
890
|
+
║ ✅ All Tasks Completed ║
|
|
891
|
+
╠═══════════════════════════════════════════════════════════════╣
|
|
892
|
+
║ ║
|
|
893
|
+
║ Issue: #[NUMBER] - [TITLE] ║
|
|
894
|
+
║ Commit: [SHORT_SHA] - [COMMIT_MSG_FIRST_LINE] ║
|
|
895
|
+
║ Tasks: [X] completed ║
|
|
896
|
+
║ ║
|
|
897
|
+
╠═══════════════════════════════════════════════════════════════╣
|
|
898
|
+
║ [C] Close issue with comment ║
|
|
899
|
+
║ [P] Push to origin + close issue ║
|
|
900
|
+
║ [K] Keep issue open ║
|
|
901
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
902
|
+
```
|
|
903
|
+
|
|
904
|
+
Then ask:
|
|
905
|
+
|
|
906
|
+
```
|
|
907
|
+
header: "Issue"
|
|
908
|
+
question: "All tasks complete. Close issue #[NUMBER]?"
|
|
909
|
+
options:
|
|
910
|
+
- label: "C - Close with comment"
|
|
911
|
+
description: "Add completion summary and close"
|
|
912
|
+
- label: "P - Push + Close"
|
|
913
|
+
description: "Push commit to origin, then close"
|
|
914
|
+
- label: "K - Keep open"
|
|
915
|
+
description: "Leave issue open for follow-up"
|
|
916
|
+
```
|
|
917
|
+
|
|
918
|
+
**Handle Close Actions:**
|
|
919
|
+
|
|
920
|
+
**C (Close with comment):**
|
|
921
|
+
```bash
|
|
922
|
+
gh issue close [NUMBER] --comment "All tasks completed in commit [SHA].
|
|
923
|
+
|
|
924
|
+
## Completed Tasks
|
|
925
|
+
- ✅ Task 1
|
|
926
|
+
- ✅ Task 2
|
|
927
|
+
...
|
|
928
|
+
|
|
929
|
+
Ready for release."
|
|
930
|
+
```
|
|
931
|
+
|
|
932
|
+
**P (Push + Close):**
|
|
933
|
+
```bash
|
|
934
|
+
git push origin HEAD
|
|
935
|
+
gh issue close [NUMBER] --comment "All tasks completed and pushed in commit [SHA].
|
|
936
|
+
|
|
937
|
+
## Completed Tasks
|
|
938
|
+
- ✅ Task 1
|
|
939
|
+
- ✅ Task 2
|
|
940
|
+
...
|
|
941
|
+
|
|
942
|
+
Ready for release."
|
|
943
|
+
```
|
|
944
|
+
|
|
945
|
+
**K (Keep open):**
|
|
946
|
+
Display: "Issue #[NUMBER] kept open for follow-up."
|
|
947
|
+
|
|
948
|
+
---
|
|
949
|
+
|
|
877
950
|
## ERROR HANDLING
|
|
878
951
|
|
|
879
952
|
| Situation | Action |
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Re-run tech stack detection and update configuration
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /detect-tech-stack - Tech Stack Analysis
|
|
6
|
+
|
|
7
|
+
Re-analyze the project's tech stack and update `.claude/config/tech-stack.json`.
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Issue #8: Tech stack detection previously only ran during terminal phase (ccasp init).
|
|
12
|
+
This command allows re-running detection from within Claude CLI to:
|
|
13
|
+
- Detect new dependencies added since initial setup
|
|
14
|
+
- Update framework versions
|
|
15
|
+
- Refresh configuration for agents, skills, and hooks
|
|
16
|
+
|
|
17
|
+
## Execution Steps
|
|
18
|
+
|
|
19
|
+
### Step 1: Read Current Tech Stack
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
cat .claude/config/tech-stack.json 2>/dev/null || echo "{}"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Save as `previousStack` for comparison.
|
|
26
|
+
|
|
27
|
+
### Step 2: Detect Current Stack
|
|
28
|
+
|
|
29
|
+
Analyze the following files to build the new tech stack:
|
|
30
|
+
|
|
31
|
+
**Package Managers:**
|
|
32
|
+
- `package.json` → Node.js/npm project
|
|
33
|
+
- `pyproject.toml` or `requirements.txt` → Python project
|
|
34
|
+
- `Cargo.toml` → Rust project
|
|
35
|
+
- `go.mod` → Go project
|
|
36
|
+
- `pom.xml` or `build.gradle` → Java project
|
|
37
|
+
|
|
38
|
+
**Frontend Frameworks (from package.json):**
|
|
39
|
+
- `react` → React
|
|
40
|
+
- `vue` → Vue.js
|
|
41
|
+
- `@angular/core` → Angular
|
|
42
|
+
- `svelte` → Svelte
|
|
43
|
+
- `next` → Next.js
|
|
44
|
+
- `nuxt` → Nuxt.js
|
|
45
|
+
- `vite` → Vite bundler
|
|
46
|
+
|
|
47
|
+
**Backend Frameworks:**
|
|
48
|
+
- `express` → Express.js
|
|
49
|
+
- `fastify` → Fastify
|
|
50
|
+
- `@nestjs/core` → NestJS
|
|
51
|
+
- `fastapi` (Python) → FastAPI
|
|
52
|
+
- `django` (Python) → Django
|
|
53
|
+
- `flask` (Python) → Flask
|
|
54
|
+
|
|
55
|
+
**Testing Frameworks:**
|
|
56
|
+
- `jest` → Jest
|
|
57
|
+
- `vitest` → Vitest
|
|
58
|
+
- `playwright` → Playwright
|
|
59
|
+
- `cypress` → Cypress
|
|
60
|
+
- `pytest` (Python) → Pytest
|
|
61
|
+
|
|
62
|
+
**Database:**
|
|
63
|
+
- `prisma` → Prisma ORM
|
|
64
|
+
- `drizzle-orm` → Drizzle
|
|
65
|
+
- `mongoose` → MongoDB
|
|
66
|
+
- `pg` or `postgres` → PostgreSQL
|
|
67
|
+
- `mysql2` → MySQL
|
|
68
|
+
|
|
69
|
+
**Deployment:**
|
|
70
|
+
Check for config files:
|
|
71
|
+
- `wrangler.toml` → Cloudflare
|
|
72
|
+
- `railway.json` or `railway.toml` → Railway
|
|
73
|
+
- `vercel.json` → Vercel
|
|
74
|
+
- `netlify.toml` → Netlify
|
|
75
|
+
- `Dockerfile` → Docker
|
|
76
|
+
|
|
77
|
+
### Step 3: Compare and Report Changes
|
|
78
|
+
|
|
79
|
+
Compare `previousStack` with newly detected stack:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
83
|
+
║ 📊 Tech Stack Analysis ║
|
|
84
|
+
╠═══════════════════════════════════════════════════════════════╣
|
|
85
|
+
║ ║
|
|
86
|
+
║ Language: {{language}} ║
|
|
87
|
+
║ Frontend: {{frontend.framework}} + {{frontend.bundler}} ║
|
|
88
|
+
║ Backend: {{backend.framework}} ║
|
|
89
|
+
║ Database: {{database.type}} ║
|
|
90
|
+
║ Testing: {{testing.frameworks}} ║
|
|
91
|
+
║ Deploy: {{deployment.platform}} ║
|
|
92
|
+
║ ║
|
|
93
|
+
╠═══════════════════════════════════════════════════════════════╣
|
|
94
|
+
║ Changes Detected: ║
|
|
95
|
+
║ [+] Added: (list new dependencies) ║
|
|
96
|
+
║ [-] Removed: (list removed dependencies) ║
|
|
97
|
+
║ [~] Updated: (list version changes) ║
|
|
98
|
+
║ ║
|
|
99
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Step 4: Update tech-stack.json
|
|
103
|
+
|
|
104
|
+
Write the updated configuration:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Backup current config
|
|
108
|
+
cp .claude/config/tech-stack.json .claude/config/tech-stack.json.bak
|
|
109
|
+
|
|
110
|
+
# Write new config (use actual detected values)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Step 5: Suggest Agent/Skill Updates
|
|
114
|
+
|
|
115
|
+
Based on detected changes, recommend:
|
|
116
|
+
|
|
117
|
+
| Change | Recommendation |
|
|
118
|
+
|--------|----------------|
|
|
119
|
+
| Added Playwright | Enable E2E testing skill |
|
|
120
|
+
| Added Prisma | Enable database agent |
|
|
121
|
+
| Added React 19 | Update component patterns |
|
|
122
|
+
| New test framework | Configure test runner |
|
|
123
|
+
|
|
124
|
+
## Output
|
|
125
|
+
|
|
126
|
+
After completion, display:
|
|
127
|
+
|
|
128
|
+
1. **Summary** of detected tech stack
|
|
129
|
+
2. **Diff** showing what changed since last detection
|
|
130
|
+
3. **Recommendations** for updating CCASP configuration
|
|
131
|
+
4. **Restart reminder** if significant changes detected
|
|
132
|
+
|
|
133
|
+
## Related Commands
|
|
134
|
+
|
|
135
|
+
- `/claude-audit` - Audit CLAUDE.md configuration
|
|
136
|
+
- `/update-smart` - Smart update manager
|
|
137
|
+
- `/project-impl` - Project implementation agent
|
|
@@ -260,6 +260,78 @@ gh issue edit [NUMBER] --body "$(gh issue view [NUMBER] --json body -q .body)
|
|
|
260
260
|
|
|
261
261
|
---
|
|
262
262
|
|
|
263
|
+
### Step 6: After Task Completion - Close Issue Prompt
|
|
264
|
+
|
|
265
|
+
**CRITICAL: After ALL TodoWrite tasks are marked complete AND a commit is created, ALWAYS offer to close the issue.**
|
|
266
|
+
|
|
267
|
+
This step triggers when:
|
|
268
|
+
1. All tasks in TodoWrite are marked `completed`
|
|
269
|
+
2. A git commit has been made with changes
|
|
270
|
+
|
|
271
|
+
Display completion summary:
|
|
272
|
+
|
|
273
|
+
```
|
|
274
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
275
|
+
║ ✅ All Tasks Completed ║
|
|
276
|
+
╠═══════════════════════════════════════════════════════════════╣
|
|
277
|
+
║ ║
|
|
278
|
+
║ Issue: #[NUMBER] - [TITLE] ║
|
|
279
|
+
║ Commit: [SHORT_SHA] - [COMMIT_MSG_FIRST_LINE] ║
|
|
280
|
+
║ Tasks: [X] completed ║
|
|
281
|
+
║ ║
|
|
282
|
+
╠═══════════════════════════════════════════════════════════════╣
|
|
283
|
+
║ [C] Close issue with comment ║
|
|
284
|
+
║ [P] Push to origin + close issue ║
|
|
285
|
+
║ [K] Keep issue open ║
|
|
286
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Then ask:
|
|
290
|
+
|
|
291
|
+
```
|
|
292
|
+
header: "Issue"
|
|
293
|
+
question: "All tasks complete. Close issue #[NUMBER]?"
|
|
294
|
+
options:
|
|
295
|
+
- label: "C - Close with comment"
|
|
296
|
+
description: "Add completion summary and close"
|
|
297
|
+
- label: "P - Push + Close"
|
|
298
|
+
description: "Push commit to origin, then close"
|
|
299
|
+
- label: "K - Keep open"
|
|
300
|
+
description: "Leave issue open for follow-up"
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**Handle Close Actions:**
|
|
304
|
+
|
|
305
|
+
**C (Close with comment):**
|
|
306
|
+
```bash
|
|
307
|
+
gh issue close [NUMBER] --comment "All tasks completed in commit [SHA].
|
|
308
|
+
|
|
309
|
+
## Completed Tasks
|
|
310
|
+
- ✅ Task 1
|
|
311
|
+
- ✅ Task 2
|
|
312
|
+
...
|
|
313
|
+
|
|
314
|
+
Ready for release."
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**P (Push + Close):**
|
|
318
|
+
```bash
|
|
319
|
+
git push origin HEAD
|
|
320
|
+
gh issue close [NUMBER] --comment "All tasks completed and pushed in commit [SHA].
|
|
321
|
+
|
|
322
|
+
## Completed Tasks
|
|
323
|
+
- ✅ Task 1
|
|
324
|
+
- ✅ Task 2
|
|
325
|
+
...
|
|
326
|
+
|
|
327
|
+
Ready for release."
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**K (Keep open):**
|
|
331
|
+
Display: "Issue #[NUMBER] kept open for follow-up."
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
263
335
|
## MOBILE OPTIMIZATION
|
|
264
336
|
|
|
265
337
|
- Single character inputs (A, B, C, S, V, X)
|
|
@@ -89,15 +89,50 @@ function getCurrentVersion() {
|
|
|
89
89
|
|
|
90
90
|
/**
|
|
91
91
|
* Check npm for latest version
|
|
92
|
+
* Issue #8: Added npm registry API fallback for Windows compatibility
|
|
92
93
|
*/
|
|
93
94
|
function checkLatestVersion() {
|
|
95
|
+
// Try npm CLI first
|
|
94
96
|
try {
|
|
95
97
|
const result = execSync(`npm view ${PACKAGE_NAME} version`, {
|
|
96
98
|
encoding: 'utf8',
|
|
97
99
|
timeout: 10000,
|
|
98
100
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
99
101
|
});
|
|
100
|
-
|
|
102
|
+
const version = result.trim();
|
|
103
|
+
if (version && /^\d+\.\d+\.\d+/.test(version)) {
|
|
104
|
+
return version;
|
|
105
|
+
}
|
|
106
|
+
} catch {
|
|
107
|
+
// npm CLI failed, try fallback
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Fallback: Direct npm registry API call
|
|
111
|
+
try {
|
|
112
|
+
const https = require('https');
|
|
113
|
+
return new Promise((resolve) => {
|
|
114
|
+
const req = https.get(
|
|
115
|
+
`https://registry.npmjs.org/${PACKAGE_NAME}/latest`,
|
|
116
|
+
{ timeout: 8000 },
|
|
117
|
+
(res) => {
|
|
118
|
+
let data = '';
|
|
119
|
+
res.on('data', (chunk) => (data += chunk));
|
|
120
|
+
res.on('end', () => {
|
|
121
|
+
try {
|
|
122
|
+
const pkg = JSON.parse(data);
|
|
123
|
+
resolve(pkg.version || null);
|
|
124
|
+
} catch {
|
|
125
|
+
resolve(null);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
);
|
|
130
|
+
req.on('error', () => resolve(null));
|
|
131
|
+
req.on('timeout', () => {
|
|
132
|
+
req.destroy();
|
|
133
|
+
resolve(null);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
101
136
|
} catch {
|
|
102
137
|
return null;
|
|
103
138
|
}
|