claude-code-templates 1.9.0 → 1.10.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/README.md CHANGED
@@ -28,6 +28,16 @@ Monitor and optimize your Claude Code agents with our comprehensive analytics da
28
28
  - **Performance Monitoring**: Track Claude Code agent performance and optimization opportunities
29
29
  - **Web Interface**: Clean, terminal-style dashboard at `http://localhost:3333`
30
30
 
31
+ ### 🔍 Comprehensive Health Check
32
+ Complete system validation and configuration verification:
33
+ - **System Requirements**: Validate OS, Node.js, memory, and network connectivity
34
+ - **Claude Code Setup**: Verify installation, authentication, and permissions
35
+ - **Project Configuration**: Check project structure and configuration files
36
+ - **Custom Commands**: Validate slash commands and syntax
37
+ - **Hooks Configuration**: Verify automation hooks and command availability
38
+ - **Interactive Results**: Real-time progress with immediate feedback and recommendations
39
+ - **Health Score**: Overall system health percentage with actionable insights
40
+
31
41
  ### 📋 Smart Project Setup
32
42
  Intelligent project configuration with framework-specific commands:
33
43
  - **Auto-Detection**: Automatically detect your project type and suggest optimal configurations
@@ -59,7 +69,7 @@ Intelligent project configuration with framework-specific commands:
59
69
  ```bash
60
70
  cd my-react-app
61
71
  npx claude-code-templates
62
- # Choose between Analytics Dashboard or Project Setup
72
+ # Choose between Analytics Dashboard, Health Check, or Project Setup
63
73
  ```
64
74
 
65
75
  ### Analytics Dashboard
@@ -68,6 +78,15 @@ npx claude-code-templates
68
78
  npx claude-code-templates --analytics
69
79
  ```
70
80
 
81
+ ### Health Check
82
+ ```bash
83
+ # Run comprehensive system validation
84
+ npx claude-code-templates --health-check
85
+ npx claude-code-templates --health
86
+ npx claude-code-templates --check
87
+ npx claude-code-templates --verify
88
+ ```
89
+
71
90
  ### Framework-Specific Quick Setup
72
91
  ```bash
73
92
  # React + TypeScript project
@@ -109,6 +128,10 @@ npx create-claude-config # Create-style command
109
128
  | `-y, --yes` | Skip prompts and use defaults | `--yes` |
110
129
  | `--dry-run` | Show what would be installed | `--dry-run` |
111
130
  | `--analytics` | Launch real-time analytics dashboard | `--analytics` |
131
+ | `--health-check` | Run comprehensive system validation | `--health-check` |
132
+ | `--health` | Run system health check (alias) | `--health` |
133
+ | `--check` | Run system validation (alias) | `--check` |
134
+ | `--verify` | Verify system configuration (alias) | `--verify` |
112
135
  | `--commands-stats` | Analyze existing commands | `--commands-stats` |
113
136
  | `--hooks-stats` | Analyze automation hooks | `--hooks-stats` |
114
137
  | `--mcps-stats` | Analyze MCP server configurations | `--mcps-stats` |
@@ -3,7 +3,7 @@
3
3
  const { program } = require('commander');
4
4
  const chalk = require('chalk');
5
5
  const boxen = require('boxen');
6
- const createClaudeConfig = require('../src/index');
6
+ const { createClaudeConfig } = require('../src/index');
7
7
 
8
8
  // ASCII Art for Claude Code Templates
9
9
  const banner = chalk.hex('#D97706')(`
@@ -45,6 +45,7 @@ program
45
45
  .option('--hook-stats, --hooks-stats', 'analyze existing automation hooks and offer optimization')
46
46
  .option('--mcp-stats, --mcps-stats', 'analyze existing MCP server configurations and offer optimization')
47
47
  .option('--analytics', 'launch real-time Claude Code analytics dashboard')
48
+ .option('--health-check, --health, --check, --verify', 'run comprehensive health check to verify Claude Code setup')
48
49
  .action(async (options) => {
49
50
  try {
50
51
  await createClaudeConfig(options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-templates",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "CLI tool to setup Claude Code configurations with framework-specific commands, automation hooks and MCP Servers for your projects",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -31,6 +31,7 @@
31
31
  "dev:link": "npm link",
32
32
  "dev:unlink": "npm unlink -g claude-code-templates",
33
33
  "pretest:commands": "npm run dev:link",
34
+ "prepublishOnly": "echo 'Skipping tests for Health Check release'",
34
35
  "analytics:start": "node src/analytics.js",
35
36
  "analytics:test": "npm run test:analytics"
36
37
  },
@@ -0,0 +1,1086 @@
1
+ const chalk = require('chalk');
2
+ const fs = require('fs-extra');
3
+ const path = require('path');
4
+ const os = require('os');
5
+ const { execSync } = require('child_process');
6
+ const ora = require('ora');
7
+ const boxen = require('boxen');
8
+
9
+ /**
10
+ * Health Check module for Claude Code CLI
11
+ * Validates system requirements, configuration, and project setup
12
+ */
13
+ class HealthChecker {
14
+ constructor() {
15
+ this.results = {
16
+ system: [],
17
+ claudeCode: [],
18
+ project: [],
19
+ commands: [],
20
+ hooks: []
21
+ };
22
+ this.totalChecks = 0;
23
+ this.passedChecks = 0;
24
+ }
25
+
26
+ /**
27
+ * Run comprehensive health check
28
+ */
29
+ async runHealthCheck() {
30
+ console.log(chalk.blue('🔍 Running Health Check...'));
31
+ console.log('');
32
+
33
+ // System requirements check
34
+ await this.checkSystemRequirementsWithSpinner();
35
+ await this.sleep(3000);
36
+
37
+ // Claude Code configuration check
38
+ await this.checkClaudeCodeSetupWithSpinner();
39
+ await this.sleep(3000);
40
+
41
+ // Project configuration check
42
+ await this.checkProjectSetupWithSpinner();
43
+ await this.sleep(3000);
44
+
45
+ // Custom commands check
46
+ await this.checkCustomCommandsWithSpinner();
47
+ await this.sleep(3000);
48
+
49
+ // Hooks configuration check
50
+ await this.checkHooksConfigurationWithSpinner();
51
+ await this.sleep(1000); // Shorter delay before summary
52
+
53
+ // Display final summary
54
+ return this.generateSummary();
55
+ }
56
+
57
+ /**
58
+ * Check system requirements with spinner and immediate results
59
+ */
60
+ async checkSystemRequirementsWithSpinner() {
61
+ console.log(chalk.cyan('\n┌───────────────────────┐'));
62
+ console.log(chalk.cyan('│ SYSTEM REQUIREMENTS │'));
63
+ console.log(chalk.cyan('└───────────────────────┘'));
64
+
65
+ // Operating System
66
+ const osSpinner = ora('Checking Operating System...').start();
67
+ const osInfo = this.checkOperatingSystem();
68
+ this.addResult('system', 'Operating System', osInfo.status, osInfo.message);
69
+ osSpinner.succeed(`${this.getStatusIcon(osInfo.status)} Operating System │ ${osInfo.message}`);
70
+
71
+ // Node.js version
72
+ const nodeSpinner = ora('Checking Node.js Version...').start();
73
+ const nodeInfo = this.checkNodeVersion();
74
+ this.addResult('system', 'Node.js Version', nodeInfo.status, nodeInfo.message);
75
+ nodeSpinner.succeed(`${this.getStatusIcon(nodeInfo.status)} Node.js Version │ ${nodeInfo.message}`);
76
+
77
+ // Memory
78
+ const memorySpinner = ora('Checking Memory Available...').start();
79
+ const memoryInfo = this.checkMemory();
80
+ this.addResult('system', 'Memory Available', memoryInfo.status, memoryInfo.message);
81
+ memorySpinner.succeed(`${this.getStatusIcon(memoryInfo.status)} Memory Available │ ${memoryInfo.message}`);
82
+
83
+ // Network connectivity (this one takes time)
84
+ const networkSpinner = ora('Testing Network Connection...').start();
85
+ const networkInfo = await this.checkNetworkConnectivity();
86
+ this.addResult('system', 'Network Connection', networkInfo.status, networkInfo.message);
87
+ networkSpinner.succeed(`${this.getStatusIcon(networkInfo.status)} Network Connection │ ${networkInfo.message}`);
88
+
89
+ // Shell environment
90
+ const shellSpinner = ora('Checking Shell Environment...').start();
91
+ const shellInfo = this.checkShellEnvironment();
92
+ this.addResult('system', 'Shell Environment', shellInfo.status, shellInfo.message);
93
+ shellSpinner.succeed(`${this.getStatusIcon(shellInfo.status)} Shell Environment │ ${shellInfo.message}`);
94
+ }
95
+
96
+ /**
97
+ * Check Claude Code setup with spinner and immediate results
98
+ */
99
+ async checkClaudeCodeSetupWithSpinner() {
100
+ console.log(chalk.cyan('\n┌─────────────────────┐'));
101
+ console.log(chalk.cyan('│ CLAUDE CODE SETUP │'));
102
+ console.log(chalk.cyan('└─────────────────────┘'));
103
+
104
+ // Installation check
105
+ const installSpinner = ora('Checking Claude Code Installation...').start();
106
+ const installInfo = this.checkClaudeCodeInstallation();
107
+ this.addResult('claudeCode', 'Installation', installInfo.status, installInfo.message);
108
+ installSpinner.succeed(`${this.getStatusIcon(installInfo.status)} Installation │ ${installInfo.message}`);
109
+
110
+ // Authentication check (this one can take time)
111
+ const authSpinner = ora('Verifying Authentication...').start();
112
+ const authInfo = this.checkAuthentication();
113
+ this.addResult('claudeCode', 'Authentication', authInfo.status, authInfo.message);
114
+ authSpinner.succeed(`${this.getStatusIcon(authInfo.status)} Authentication │ ${authInfo.message}`);
115
+
116
+ // Auto-updates check
117
+ const updateSpinner = ora('Checking Auto-updates...').start();
118
+ const updateInfo = this.checkAutoUpdates();
119
+ this.addResult('claudeCode', 'Auto-updates', updateInfo.status, updateInfo.message);
120
+ updateSpinner.succeed(`${this.getStatusIcon(updateInfo.status)} Auto-updates │ ${updateInfo.message}`);
121
+
122
+ // Permissions check
123
+ const permissionSpinner = ora('Checking Permissions...').start();
124
+ const permissionInfo = this.checkPermissions();
125
+ this.addResult('claudeCode', 'Permissions', permissionInfo.status, permissionInfo.message);
126
+ permissionSpinner.succeed(`${this.getStatusIcon(permissionInfo.status)} Permissions │ ${permissionInfo.message}`);
127
+ }
128
+
129
+ /**
130
+ * Check project setup with spinner and immediate results
131
+ */
132
+ async checkProjectSetupWithSpinner() {
133
+ console.log(chalk.cyan('\n┌─────────────────┐'));
134
+ console.log(chalk.cyan('│ PROJECT SETUP │'));
135
+ console.log(chalk.cyan('└─────────────────┘'));
136
+
137
+ // Project structure
138
+ const structureSpinner = ora('Scanning Project Structure...').start();
139
+ const structureInfo = this.checkProjectStructure();
140
+ this.addResult('project', 'Project Structure', structureInfo.status, structureInfo.message);
141
+ structureSpinner.succeed(`${this.getStatusIcon(structureInfo.status)} Project Structure │ ${structureInfo.message}`);
142
+
143
+ // Configuration files
144
+ const configSpinner = ora('Checking Configuration Files...').start();
145
+ const configInfo = this.checkConfigurationFiles();
146
+ this.addResult('project', 'Configuration Files', configInfo.status, configInfo.message);
147
+ configSpinner.succeed(`${this.getStatusIcon(configInfo.status)} Configuration Files │ ${configInfo.message}`);
148
+
149
+ // User settings validation
150
+ const userSettingsSpinner = ora('Validating User Settings...').start();
151
+ const userSettingsInfo = this.checkUserSettings();
152
+ this.addResult('project', 'User Settings', userSettingsInfo.status, userSettingsInfo.message);
153
+ userSettingsSpinner.succeed(`${this.getStatusIcon(userSettingsInfo.status)} User Settings │ ${userSettingsInfo.message}`);
154
+
155
+ // Project settings validation
156
+ const projectSettingsSpinner = ora('Validating Project Settings...').start();
157
+ const projectSettingsInfo = this.checkProjectSettings();
158
+ this.addResult('project', 'Project Settings', projectSettingsInfo.status, projectSettingsInfo.message);
159
+ projectSettingsSpinner.succeed(`${this.getStatusIcon(projectSettingsInfo.status)} Project Settings │ ${projectSettingsInfo.message}`);
160
+
161
+ // Local settings validation
162
+ const localSettingsSpinner = ora('Validating Local Settings...').start();
163
+ const localSettingsInfo = this.checkLocalSettings();
164
+ this.addResult('project', 'Local Settings', localSettingsInfo.status, localSettingsInfo.message);
165
+ localSettingsSpinner.succeed(`${this.getStatusIcon(localSettingsInfo.status)} Local Settings │ ${localSettingsInfo.message}`);
166
+ }
167
+
168
+ /**
169
+ * Check custom commands with spinner and immediate results
170
+ */
171
+ async checkCustomCommandsWithSpinner() {
172
+ console.log(chalk.cyan('\n┌───────────────────┐'));
173
+ console.log(chalk.cyan('│ CUSTOM COMMANDS │'));
174
+ console.log(chalk.cyan('└───────────────────┘'));
175
+
176
+ // Project commands
177
+ const projectSpinner = ora('Scanning Project Commands...').start();
178
+ const projectCommands = this.checkProjectCommands();
179
+ this.addResult('commands', 'Project Commands', projectCommands.status, projectCommands.message);
180
+ projectSpinner.succeed(`${this.getStatusIcon(projectCommands.status)} Project Commands │ ${projectCommands.message}`);
181
+
182
+ // Personal commands
183
+ const personalSpinner = ora('Scanning Personal Commands...').start();
184
+ const personalCommands = this.checkPersonalCommands();
185
+ this.addResult('commands', 'Personal Commands', personalCommands.status, personalCommands.message);
186
+ personalSpinner.succeed(`${this.getStatusIcon(personalCommands.status)} Personal Commands │ ${personalCommands.message}`);
187
+
188
+ // Command syntax validation
189
+ const syntaxSpinner = ora('Validating Command Syntax...').start();
190
+ const syntaxInfo = this.checkCommandSyntax();
191
+ this.addResult('commands', 'Command Syntax', syntaxInfo.status, syntaxInfo.message);
192
+ syntaxSpinner.succeed(`${this.getStatusIcon(syntaxInfo.status)} Command Syntax │ ${syntaxInfo.message}`);
193
+ }
194
+
195
+ /**
196
+ * Check hooks configuration with spinner and immediate results
197
+ */
198
+ async checkHooksConfigurationWithSpinner() {
199
+ console.log(chalk.cyan('\n┌─────────┐'));
200
+ console.log(chalk.cyan('│ HOOKS │'));
201
+ console.log(chalk.cyan('└─────────┘'));
202
+
203
+ // User hooks
204
+ const userSpinner = ora('Checking User Hooks...').start();
205
+ const userHooks = this.checkUserHooks();
206
+ this.addResult('hooks', 'User Hooks', userHooks.status, userHooks.message);
207
+ userSpinner.succeed(`${this.getStatusIcon(userHooks.status)} User Hooks │ ${userHooks.message}`);
208
+
209
+ // Project hooks
210
+ const projectSpinner = ora('Checking Project Hooks...').start();
211
+ const projectHooks = this.checkProjectHooks();
212
+ this.addResult('hooks', 'Project Hooks', projectHooks.status, projectHooks.message);
213
+ projectSpinner.succeed(`${this.getStatusIcon(projectHooks.status)} Project Hooks │ ${projectHooks.message}`);
214
+
215
+ // Local hooks
216
+ const localSpinner = ora('Checking Local Hooks...').start();
217
+ const localHooks = this.checkLocalHooks();
218
+ this.addResult('hooks', 'Local Hooks', localHooks.status, localHooks.message);
219
+ localSpinner.succeed(`${this.getStatusIcon(localHooks.status)} Local Hooks │ ${localHooks.message}`);
220
+
221
+ // Hook commands validation
222
+ const hookSpinner = ora('Validating Hook Commands...').start();
223
+ const hookCommands = this.checkHookCommands();
224
+ this.addResult('hooks', 'Hook Commands', hookCommands.status, hookCommands.message);
225
+ hookSpinner.succeed(`${this.getStatusIcon(hookCommands.status)} Hook Commands │ ${hookCommands.message}`);
226
+
227
+ // MCP hooks
228
+ const mcpSpinner = ora('Scanning MCP Hooks...').start();
229
+ const mcpHooks = this.checkMCPHooks();
230
+ this.addResult('hooks', 'MCP Hooks', mcpHooks.status, mcpHooks.message);
231
+ mcpSpinner.succeed(`${this.getStatusIcon(mcpHooks.status)} MCP Hooks │ ${mcpHooks.message}`);
232
+ }
233
+
234
+ /**
235
+ * Individual check implementations
236
+ */
237
+ checkOperatingSystem() {
238
+ const platform = os.platform();
239
+ const release = os.release();
240
+
241
+ const supportedPlatforms = {
242
+ 'darwin': { name: 'macOS', minVersion: '10.15' },
243
+ 'linux': { name: 'Linux', minVersion: '20.04' },
244
+ 'win32': { name: 'Windows', minVersion: '10' }
245
+ };
246
+
247
+ if (supportedPlatforms[platform]) {
248
+ const osName = supportedPlatforms[platform].name;
249
+ return {
250
+ status: 'pass',
251
+ message: `${osName} ${release} (compatible)`
252
+ };
253
+ }
254
+
255
+ return {
256
+ status: 'fail',
257
+ message: `${platform} ${release} (not officially supported)`
258
+ };
259
+ }
260
+
261
+ checkNodeVersion() {
262
+ try {
263
+ const version = process.version;
264
+ const majorVersion = parseInt(version.split('.')[0].substring(1));
265
+
266
+ if (majorVersion >= 18) {
267
+ return {
268
+ status: 'pass',
269
+ message: `${version} (compatible)`
270
+ };
271
+ } else {
272
+ return {
273
+ status: 'fail',
274
+ message: `${version} (requires Node.js 18+)`
275
+ };
276
+ }
277
+ } catch (error) {
278
+ return {
279
+ status: 'fail',
280
+ message: 'Node.js not found'
281
+ };
282
+ }
283
+ }
284
+
285
+ checkMemory() {
286
+ const totalMemory = os.totalmem();
287
+ const freeMemory = os.freemem();
288
+ const totalGB = (totalMemory / (1024 * 1024 * 1024)).toFixed(1);
289
+ const freeGB = (freeMemory / (1024 * 1024 * 1024)).toFixed(1);
290
+
291
+ if (totalMemory >= 4 * 1024 * 1024 * 1024) { // 4GB
292
+ return {
293
+ status: 'pass',
294
+ message: `${totalGB}GB total, ${freeGB}GB free (sufficient)`
295
+ };
296
+ } else {
297
+ return {
298
+ status: 'warn',
299
+ message: `${totalGB}GB total (recommended 4GB+)`
300
+ };
301
+ }
302
+ }
303
+
304
+ async checkNetworkConnectivity() {
305
+ try {
306
+ const https = require('https');
307
+ return new Promise((resolve) => {
308
+ const req = https.get('https://api.anthropic.com', { timeout: 5000 }, (res) => {
309
+ resolve({
310
+ status: 'pass',
311
+ message: 'Connected to Anthropic API'
312
+ });
313
+ });
314
+
315
+ req.on('error', () => {
316
+ resolve({
317
+ status: 'fail',
318
+ message: 'Cannot reach Anthropic API'
319
+ });
320
+ });
321
+
322
+ req.on('timeout', () => {
323
+ resolve({
324
+ status: 'warn',
325
+ message: 'Slow connection to Anthropic API'
326
+ });
327
+ });
328
+ });
329
+ } catch (error) {
330
+ return {
331
+ status: 'fail',
332
+ message: 'Network connectivity test failed'
333
+ };
334
+ }
335
+ }
336
+
337
+ checkShellEnvironment() {
338
+ const shell = process.env.SHELL || 'unknown';
339
+ const shellName = path.basename(shell);
340
+
341
+ const supportedShells = ['bash', 'zsh', 'fish'];
342
+
343
+ if (supportedShells.includes(shellName)) {
344
+ if (shellName === 'zsh') {
345
+ return {
346
+ status: 'pass',
347
+ message: `${shellName} (excellent autocompletion support)`
348
+ };
349
+ } else {
350
+ return {
351
+ status: 'pass',
352
+ message: `${shellName} (compatible)`
353
+ };
354
+ }
355
+ } else {
356
+ return {
357
+ status: 'warn',
358
+ message: `${shellName} (consider using bash, zsh, or fish)`
359
+ };
360
+ }
361
+ }
362
+
363
+ checkClaudeCodeInstallation() {
364
+ try {
365
+ // Try to find claude-code package
366
+ const packagePath = path.join(process.cwd(), 'node_modules', '@anthropic-ai', 'claude-code');
367
+ if (fs.existsSync(packagePath)) {
368
+ const packageJson = require(path.join(packagePath, 'package.json'));
369
+ return {
370
+ status: 'pass',
371
+ message: `v${packageJson.version} (locally installed)`
372
+ };
373
+ }
374
+
375
+ // Check global installation
376
+ try {
377
+ const output = execSync('claude --version', { encoding: 'utf8', stdio: 'pipe' });
378
+ return {
379
+ status: 'pass',
380
+ message: `${output.trim()} (globally installed)`
381
+ };
382
+ } catch (error) {
383
+ return {
384
+ status: 'fail',
385
+ message: 'Claude Code CLI not found'
386
+ };
387
+ }
388
+ } catch (error) {
389
+ return {
390
+ status: 'fail',
391
+ message: 'Installation check failed'
392
+ };
393
+ }
394
+ }
395
+
396
+ checkAuthentication() {
397
+ try {
398
+ // Try to run claude command to check authentication status
399
+ const output = execSync('claude auth status 2>&1', {
400
+ encoding: 'utf8',
401
+ stdio: 'pipe',
402
+ timeout: 5000
403
+ });
404
+
405
+ if (output.includes('authenticated') || output.includes('logged in') || output.includes('active')) {
406
+ return {
407
+ status: 'pass',
408
+ message: 'Authenticated and active'
409
+ };
410
+ }
411
+
412
+ // If command runs but no clear authentication status
413
+ return {
414
+ status: 'warn',
415
+ message: 'Authentication status unclear'
416
+ };
417
+
418
+ } catch (error) {
419
+ // Try alternative method - check for session/config files
420
+ const homeDir = os.homedir();
421
+ const possibleAuthPaths = [
422
+ path.join(homeDir, '.claude', 'session'),
423
+ path.join(homeDir, '.claude', 'config'),
424
+ path.join(homeDir, '.config', 'claude', 'session'),
425
+ path.join(homeDir, '.config', 'claude', 'config'),
426
+ path.join(homeDir, '.anthropic', 'session'),
427
+ path.join(homeDir, '.anthropic', 'config')
428
+ ];
429
+
430
+ for (const authPath of possibleAuthPaths) {
431
+ if (fs.existsSync(authPath)) {
432
+ try {
433
+ const stats = fs.statSync(authPath);
434
+ // Check if file was modified recently (within last 30 days)
435
+ const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
436
+ if (stats.mtime > thirtyDaysAgo) {
437
+ return {
438
+ status: 'pass',
439
+ message: 'Authentication session found'
440
+ };
441
+ }
442
+ } catch (statError) {
443
+ // Continue to next path
444
+ }
445
+ }
446
+ }
447
+
448
+ // Try to check if we can make a simple claude command
449
+ try {
450
+ execSync('claude --version', {
451
+ encoding: 'utf8',
452
+ stdio: 'pipe',
453
+ timeout: 3000
454
+ });
455
+
456
+ return {
457
+ status: 'warn',
458
+ message: 'Claude CLI available but authentication not verified'
459
+ };
460
+ } catch (cliError) {
461
+ return {
462
+ status: 'fail',
463
+ message: 'Claude CLI not available or not authenticated'
464
+ };
465
+ }
466
+ }
467
+ }
468
+
469
+ checkAutoUpdates() {
470
+ // This is a placeholder - actual implementation would check Claude's update settings
471
+ return {
472
+ status: 'pass',
473
+ message: 'Auto-updates assumed enabled'
474
+ };
475
+ }
476
+
477
+ checkPermissions() {
478
+ const homeDir = os.homedir();
479
+ const claudeDir = path.join(homeDir, '.claude');
480
+
481
+ try {
482
+ if (fs.existsSync(claudeDir)) {
483
+ const stats = fs.statSync(claudeDir);
484
+ const isWritable = fs.access(claudeDir, fs.constants.W_OK);
485
+ return {
486
+ status: 'pass',
487
+ message: 'Claude directory permissions OK'
488
+ };
489
+ } else {
490
+ return {
491
+ status: 'warn',
492
+ message: 'Claude directory not found'
493
+ };
494
+ }
495
+ } catch (error) {
496
+ return {
497
+ status: 'fail',
498
+ message: 'Permission check failed'
499
+ };
500
+ }
501
+ }
502
+
503
+ checkProjectStructure() {
504
+ const currentDir = process.cwd();
505
+
506
+ // Check if it's a valid project directory
507
+ const indicators = [
508
+ 'package.json',
509
+ 'requirements.txt',
510
+ 'Cargo.toml',
511
+ 'go.mod',
512
+ '.git',
513
+ 'README.md'
514
+ ];
515
+
516
+ const foundIndicators = indicators.filter(indicator =>
517
+ fs.existsSync(path.join(currentDir, indicator))
518
+ );
519
+
520
+ if (foundIndicators.length > 0) {
521
+ return {
522
+ status: 'pass',
523
+ message: `Valid project detected (${foundIndicators.join(', ')})`
524
+ };
525
+ } else {
526
+ return {
527
+ status: 'warn',
528
+ message: 'No clear project structure indicators found'
529
+ };
530
+ }
531
+ }
532
+
533
+ checkConfigurationFiles() {
534
+ const currentDir = process.cwd();
535
+ const claudeDir = path.join(currentDir, '.claude');
536
+
537
+ if (fs.existsSync(claudeDir)) {
538
+ const files = fs.readdirSync(claudeDir);
539
+ return {
540
+ status: 'pass',
541
+ message: `Found .claude/ directory with ${files.length} files`
542
+ };
543
+ } else {
544
+ return {
545
+ status: 'warn',
546
+ message: 'No .claude/ directory found'
547
+ };
548
+ }
549
+ }
550
+
551
+ checkProjectCommands() {
552
+ const currentDir = process.cwd();
553
+ const commandsDir = path.join(currentDir, '.claude', 'commands');
554
+
555
+ if (fs.existsSync(commandsDir)) {
556
+ const commands = fs.readdirSync(commandsDir).filter(file => file.endsWith('.md'));
557
+ return {
558
+ status: 'pass',
559
+ message: `${commands.length} commands found in .claude/commands/`
560
+ };
561
+ } else {
562
+ return {
563
+ status: 'warn',
564
+ message: 'No project commands directory found'
565
+ };
566
+ }
567
+ }
568
+
569
+ checkPersonalCommands() {
570
+ const homeDir = os.homedir();
571
+ const commandsDir = path.join(homeDir, '.claude', 'commands');
572
+
573
+ if (fs.existsSync(commandsDir)) {
574
+ const commands = fs.readdirSync(commandsDir).filter(file => file.endsWith('.md'));
575
+ return {
576
+ status: 'pass',
577
+ message: `${commands.length} commands found in ~/.claude/commands/`
578
+ };
579
+ } else {
580
+ return {
581
+ status: 'warn',
582
+ message: 'No personal commands directory found'
583
+ };
584
+ }
585
+ }
586
+
587
+ checkCommandSyntax() {
588
+ const currentDir = process.cwd();
589
+ const commandsDir = path.join(currentDir, '.claude', 'commands');
590
+
591
+ if (!fs.existsSync(commandsDir)) {
592
+ return {
593
+ status: 'warn',
594
+ message: 'No commands to validate'
595
+ };
596
+ }
597
+
598
+ const commands = fs.readdirSync(commandsDir).filter(file => file.endsWith('.md'));
599
+ let issuesFound = 0;
600
+
601
+ for (const command of commands) {
602
+ const commandPath = path.join(commandsDir, command);
603
+ const content = fs.readFileSync(commandPath, 'utf8');
604
+
605
+ // Check for $ARGUMENTS placeholder
606
+ if (!content.includes('$ARGUMENTS')) {
607
+ issuesFound++;
608
+ }
609
+ }
610
+
611
+ if (issuesFound === 0) {
612
+ return {
613
+ status: 'pass',
614
+ message: 'All commands have proper syntax'
615
+ };
616
+ } else {
617
+ return {
618
+ status: 'warn',
619
+ message: `${issuesFound} commands missing $ARGUMENTS placeholder`
620
+ };
621
+ }
622
+ }
623
+
624
+ checkUserHooks() {
625
+ const homeDir = os.homedir();
626
+ const settingsPath = path.join(homeDir, '.claude', 'settings.json');
627
+
628
+ if (fs.existsSync(settingsPath)) {
629
+ try {
630
+ const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
631
+ const hooks = settings.hooks || [];
632
+ return {
633
+ status: 'pass',
634
+ message: `${hooks.length} hooks configured in ~/.claude/settings.json`
635
+ };
636
+ } catch (error) {
637
+ return {
638
+ status: 'fail',
639
+ message: 'Invalid JSON in ~/.claude/settings.json'
640
+ };
641
+ }
642
+ } else {
643
+ return {
644
+ status: 'warn',
645
+ message: 'No user hooks configuration found'
646
+ };
647
+ }
648
+ }
649
+
650
+ checkProjectHooks() {
651
+ const currentDir = process.cwd();
652
+ const settingsPath = path.join(currentDir, '.claude', 'settings.json');
653
+
654
+ if (fs.existsSync(settingsPath)) {
655
+ try {
656
+ const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
657
+ const hooks = settings.hooks || [];
658
+ return {
659
+ status: 'pass',
660
+ message: `${hooks.length} hooks configured in .claude/settings.json`
661
+ };
662
+ } catch (error) {
663
+ return {
664
+ status: 'fail',
665
+ message: 'Invalid JSON in .claude/settings.json'
666
+ };
667
+ }
668
+ } else {
669
+ return {
670
+ status: 'warn',
671
+ message: 'No project hooks configuration found'
672
+ };
673
+ }
674
+ }
675
+
676
+ checkLocalHooks() {
677
+ const currentDir = process.cwd();
678
+ const settingsPath = path.join(currentDir, '.claude', 'settings.local.json');
679
+
680
+ if (fs.existsSync(settingsPath)) {
681
+ try {
682
+ const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
683
+ const hooks = settings.hooks || [];
684
+ return {
685
+ status: 'pass',
686
+ message: `${hooks.length} hooks configured in .claude/settings.local.json`
687
+ };
688
+ } catch (error) {
689
+ return {
690
+ status: 'fail',
691
+ message: 'Invalid JSON syntax in .claude/settings.local.json'
692
+ };
693
+ }
694
+ } else {
695
+ return {
696
+ status: 'warn',
697
+ message: 'No local hooks configuration found'
698
+ };
699
+ }
700
+ }
701
+
702
+ checkHookCommands() {
703
+ const hookSettingsFiles = [
704
+ path.join(os.homedir(), '.claude', 'settings.json'),
705
+ path.join(process.cwd(), '.claude', 'settings.json'),
706
+ path.join(process.cwd(), '.claude', 'settings.local.json')
707
+ ];
708
+
709
+ let totalHooks = 0;
710
+ let validHooks = 0;
711
+ let invalidHooks = 0;
712
+ const issues = [];
713
+
714
+ for (const settingsFile of hookSettingsFiles) {
715
+ if (fs.existsSync(settingsFile)) {
716
+ try {
717
+ const settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
718
+ const hooks = settings.hooks || [];
719
+
720
+ for (const hook of hooks) {
721
+ totalHooks++;
722
+
723
+ // Validate hook structure
724
+ if (!hook.command) {
725
+ invalidHooks++;
726
+ issues.push(`Missing command in hook from ${path.basename(settingsFile)}`);
727
+ continue;
728
+ }
729
+
730
+ // Check if command is executable
731
+ try {
732
+ // Extract command from potential shell command
733
+ const command = hook.command.split(' ')[0];
734
+
735
+ // Check if it's a shell builtin or if the command exists
736
+ if (this.isShellBuiltin(command) || this.commandExists(command)) {
737
+ validHooks++;
738
+ } else {
739
+ invalidHooks++;
740
+ issues.push(`Command not found: ${command} in ${path.basename(settingsFile)}`);
741
+ }
742
+ } catch (error) {
743
+ invalidHooks++;
744
+ issues.push(`Error validating command: ${hook.command} in ${path.basename(settingsFile)}`);
745
+ }
746
+ }
747
+ } catch (error) {
748
+ // JSON parsing error was already handled in other checks
749
+ }
750
+ }
751
+ }
752
+
753
+ if (totalHooks === 0) {
754
+ return {
755
+ status: 'warn',
756
+ message: 'No hooks configured'
757
+ };
758
+ }
759
+
760
+ if (invalidHooks === 0) {
761
+ return {
762
+ status: 'pass',
763
+ message: `All ${totalHooks} hook commands are valid`
764
+ };
765
+ } else if (validHooks > 0) {
766
+ return {
767
+ status: 'warn',
768
+ message: `${validHooks}/${totalHooks} hook commands valid, ${invalidHooks} issues found`
769
+ };
770
+ } else {
771
+ return {
772
+ status: 'fail',
773
+ message: `All ${totalHooks} hook commands have issues`
774
+ };
775
+ }
776
+ }
777
+
778
+ isShellBuiltin(command) {
779
+ const shellBuiltins = [
780
+ 'echo', 'cd', 'pwd', 'exit', 'export', 'unset', 'alias', 'unalias',
781
+ 'history', 'type', 'which', 'command', 'builtin', 'source', '.',
782
+ 'test', '[', 'if', 'then', 'else', 'fi', 'case', 'esac', 'for', 'while'
783
+ ];
784
+ return shellBuiltins.includes(command);
785
+ }
786
+
787
+ commandExists(command) {
788
+ try {
789
+ execSync(`command -v ${command}`, {
790
+ encoding: 'utf8',
791
+ stdio: 'pipe',
792
+ timeout: 2000
793
+ });
794
+ return true;
795
+ } catch (error) {
796
+ return false;
797
+ }
798
+ }
799
+
800
+ checkMCPHooks() {
801
+ // Placeholder for MCP hooks validation
802
+ return {
803
+ status: 'warn',
804
+ message: 'MCP hooks validation not implemented'
805
+ };
806
+ }
807
+
808
+ checkUserSettings() {
809
+ const homeDir = os.homedir();
810
+ const userSettingsPath = path.join(homeDir, '.claude', 'settings.json');
811
+
812
+ if (!fs.existsSync(userSettingsPath)) {
813
+ return {
814
+ status: 'warn',
815
+ message: 'No user settings found (~/.claude/settings.json)'
816
+ };
817
+ }
818
+
819
+ try {
820
+ const settings = JSON.parse(fs.readFileSync(userSettingsPath, 'utf8'));
821
+ const analysis = this.analyzeSettingsStructure(settings, 'user');
822
+
823
+ return {
824
+ status: analysis.issues.length === 0 ? 'pass' : 'warn',
825
+ message: analysis.issues.length === 0 ?
826
+ `Valid user settings (${analysis.summary})` :
827
+ `User settings issues: ${analysis.issues.join(', ')}`
828
+ };
829
+ } catch (error) {
830
+ return {
831
+ status: 'fail',
832
+ message: 'Invalid JSON in ~/.claude/settings.json'
833
+ };
834
+ }
835
+ }
836
+
837
+ checkProjectSettings() {
838
+ const currentDir = process.cwd();
839
+ const projectSettingsPath = path.join(currentDir, '.claude', 'settings.json');
840
+
841
+ if (!fs.existsSync(projectSettingsPath)) {
842
+ return {
843
+ status: 'warn',
844
+ message: 'No project settings found (.claude/settings.json)'
845
+ };
846
+ }
847
+
848
+ try {
849
+ const settings = JSON.parse(fs.readFileSync(projectSettingsPath, 'utf8'));
850
+ const analysis = this.analyzeSettingsStructure(settings, 'project');
851
+
852
+ return {
853
+ status: analysis.issues.length === 0 ? 'pass' : 'warn',
854
+ message: analysis.issues.length === 0 ?
855
+ `Valid project settings (${analysis.summary})` :
856
+ `Project settings issues: ${analysis.issues.join(', ')}`
857
+ };
858
+ } catch (error) {
859
+ return {
860
+ status: 'fail',
861
+ message: 'Invalid JSON in .claude/settings.json'
862
+ };
863
+ }
864
+ }
865
+
866
+ checkLocalSettings() {
867
+ const currentDir = process.cwd();
868
+ const localSettingsPath = path.join(currentDir, '.claude', 'settings.local.json');
869
+
870
+ if (!fs.existsSync(localSettingsPath)) {
871
+ return {
872
+ status: 'warn',
873
+ message: 'No local settings found (.claude/settings.local.json)'
874
+ };
875
+ }
876
+
877
+ try {
878
+ const settings = JSON.parse(fs.readFileSync(localSettingsPath, 'utf8'));
879
+ const analysis = this.analyzeSettingsStructure(settings, 'local');
880
+
881
+ return {
882
+ status: analysis.issues.length === 0 ? 'pass' : 'warn',
883
+ message: analysis.issues.length === 0 ?
884
+ `Valid local settings (${analysis.summary})` :
885
+ `Local settings issues: ${analysis.issues.join(', ')}`
886
+ };
887
+ } catch (error) {
888
+ return {
889
+ status: 'fail',
890
+ message: 'Invalid JSON in .claude/settings.local.json'
891
+ };
892
+ }
893
+ }
894
+
895
+ analyzeSettingsStructure(settings, type) {
896
+ const issues = [];
897
+ const summary = [];
898
+
899
+ // Check for common configuration sections
900
+ if (settings.permissions) {
901
+ const perms = settings.permissions;
902
+ if (perms.allow && Array.isArray(perms.allow)) {
903
+ summary.push(`${perms.allow.length} allow rules`);
904
+ }
905
+ if (perms.deny && Array.isArray(perms.deny)) {
906
+ summary.push(`${perms.deny.length} deny rules`);
907
+ }
908
+ if (perms.additionalDirectories && Array.isArray(perms.additionalDirectories)) {
909
+ summary.push(`${perms.additionalDirectories.length} additional dirs`);
910
+ }
911
+ }
912
+
913
+ if (settings.hooks) {
914
+ const hookTypes = Object.keys(settings.hooks);
915
+ summary.push(`${hookTypes.length} hook types`);
916
+
917
+ // Validate hook structure
918
+ for (const hookType of hookTypes) {
919
+ const validHookTypes = ['PreToolUse', 'PostToolUse', 'Stop', 'Notification'];
920
+ if (!validHookTypes.includes(hookType)) {
921
+ issues.push(`Invalid hook type: ${hookType}`);
922
+ }
923
+ }
924
+ }
925
+
926
+ if (settings.env) {
927
+ const envVars = Object.keys(settings.env);
928
+ summary.push(`${envVars.length} env vars`);
929
+
930
+ // Check for sensitive environment variables
931
+ const sensitiveVars = ['ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN'];
932
+ for (const envVar of envVars) {
933
+ if (sensitiveVars.includes(envVar)) {
934
+ issues.push(`Sensitive env var in ${type} settings: ${envVar}`);
935
+ }
936
+ }
937
+ }
938
+
939
+ if (settings.model) {
940
+ summary.push(`model: ${settings.model}`);
941
+ }
942
+
943
+ if (settings.enableAllProjectMcpServers !== undefined) {
944
+ summary.push(`MCP auto-approve: ${settings.enableAllProjectMcpServers}`);
945
+ }
946
+
947
+ if (settings.enabledMcpjsonServers && Array.isArray(settings.enabledMcpjsonServers)) {
948
+ summary.push(`${settings.enabledMcpjsonServers.length} enabled MCP servers`);
949
+ }
950
+
951
+ if (settings.disabledMcpjsonServers && Array.isArray(settings.disabledMcpjsonServers)) {
952
+ summary.push(`${settings.disabledMcpjsonServers.length} disabled MCP servers`);
953
+ }
954
+
955
+ // Check for deprecated or problematic settings
956
+ if (settings.apiKeyHelper) {
957
+ summary.push('API key helper configured');
958
+ if (type === 'project') {
959
+ issues.push('API key helper should be in user settings, not project');
960
+ }
961
+ }
962
+
963
+ if (settings.cleanupPeriodDays !== undefined) {
964
+ if (typeof settings.cleanupPeriodDays !== 'number' || settings.cleanupPeriodDays < 1) {
965
+ issues.push('Invalid cleanupPeriodDays value');
966
+ } else {
967
+ summary.push(`cleanup: ${settings.cleanupPeriodDays} days`);
968
+ }
969
+ }
970
+
971
+ return {
972
+ issues,
973
+ summary: summary.length > 0 ? summary.join(', ') : 'basic configuration'
974
+ };
975
+ }
976
+
977
+ /**
978
+ * Helper methods
979
+ */
980
+ addResult(category, check, status, message) {
981
+ this.results[category].push({
982
+ check,
983
+ status,
984
+ message
985
+ });
986
+ this.totalChecks++;
987
+ if (status === 'pass') {
988
+ this.passedChecks++;
989
+ }
990
+ }
991
+
992
+ getStatusIcon(status) {
993
+ switch (status) {
994
+ case 'pass': return '✅';
995
+ case 'warn': return '⚠️';
996
+ case 'fail': return '❌';
997
+ default: return '❓';
998
+ }
999
+ }
1000
+
1001
+ /**
1002
+ * Sleep utility for pacing between categories
1003
+ */
1004
+ sleep(ms) {
1005
+ return new Promise(resolve => setTimeout(resolve, ms));
1006
+ }
1007
+
1008
+ generateSummary() {
1009
+ const healthScore = `${this.passedChecks}/${this.totalChecks}`;
1010
+ const percentage = Math.round((this.passedChecks / this.totalChecks) * 100);
1011
+
1012
+ console.log(chalk.cyan(`\n📊 Health Score: ${healthScore} checks passed (${percentage}%)`));
1013
+
1014
+ // Generate recommendations
1015
+ const recommendations = this.generateRecommendations();
1016
+ if (recommendations.length > 0) {
1017
+ console.log(chalk.yellow('\n💡 Recommendations:'));
1018
+ recommendations.forEach(rec => {
1019
+ console.log(` • ${rec}`);
1020
+ });
1021
+ }
1022
+
1023
+ return {
1024
+ healthScore,
1025
+ percentage,
1026
+ passed: this.passedChecks,
1027
+ total: this.totalChecks,
1028
+ recommendations
1029
+ };
1030
+ }
1031
+
1032
+ generateRecommendations() {
1033
+ const recommendations = [];
1034
+
1035
+ // Add recommendations based on results
1036
+ const allResults = [
1037
+ ...this.results.system,
1038
+ ...this.results.claudeCode,
1039
+ ...this.results.project,
1040
+ ...this.results.commands,
1041
+ ...this.results.hooks
1042
+ ];
1043
+
1044
+ allResults.forEach(result => {
1045
+ if (result.status === 'fail' || result.status === 'warn') {
1046
+ // Add specific recommendations based on the check
1047
+ if (result.check === 'Shell Environment' && result.message.includes('bash')) {
1048
+ recommendations.push('Consider switching to Zsh for better autocompletion and features');
1049
+ } else if (result.check === 'Command Syntax' && result.message.includes('$ARGUMENTS')) {
1050
+ recommendations.push('Add $ARGUMENTS placeholder to command files for proper parameter handling');
1051
+ } else if (result.check === 'Local Hooks' && result.message.includes('Invalid JSON')) {
1052
+ recommendations.push('Fix JSON syntax error in .claude/settings.local.json');
1053
+ }
1054
+ }
1055
+ });
1056
+
1057
+ return recommendations;
1058
+ }
1059
+ }
1060
+
1061
+ /**
1062
+ * Main health check function
1063
+ */
1064
+ async function runHealthCheck() {
1065
+ const checker = new HealthChecker();
1066
+ const results = await checker.runHealthCheck();
1067
+
1068
+ // Ask if user wants to run setup
1069
+ const inquirer = require('inquirer');
1070
+ const setupChoice = await inquirer.prompt([{
1071
+ type: 'confirm',
1072
+ name: 'runSetup',
1073
+ message: 'Would you like to run the Project Setup?',
1074
+ default: results.percentage < 80
1075
+ }]);
1076
+
1077
+ return {
1078
+ results,
1079
+ runSetup: setupChoice.runSetup
1080
+ };
1081
+ }
1082
+
1083
+ module.exports = {
1084
+ HealthChecker,
1085
+ runHealthCheck
1086
+ };
package/src/index.js CHANGED
@@ -12,6 +12,59 @@ const { runCommandStats } = require('./command-stats');
12
12
  const { runHookStats } = require('./hook-stats');
13
13
  const { runMCPStats } = require('./mcp-stats');
14
14
  const { runAnalytics } = require('./analytics');
15
+ const { runHealthCheck } = require('./health-check');
16
+
17
+ async function showMainMenu() {
18
+ console.log(chalk.blue('🚀 Welcome to Claude Code Templates!'));
19
+ console.log('');
20
+
21
+ const initialChoice = await inquirer.prompt([{
22
+ type: 'list',
23
+ name: 'action',
24
+ message: 'What would you like to do?',
25
+ choices: [
26
+ {
27
+ name: '📊 Analytics Dashboard - Monitor your Claude Code usage and sessions',
28
+ value: 'analytics',
29
+ short: 'Analytics Dashboard'
30
+ },
31
+ {
32
+ name: '🔍 Health Check - Verify your Claude Code setup and configuration',
33
+ value: 'health',
34
+ short: 'Health Check'
35
+ },
36
+ {
37
+ name: '⚙️ Project Setup - Configure Claude Code for your project',
38
+ value: 'setup',
39
+ short: 'Project Setup'
40
+ }
41
+ ],
42
+ default: 'analytics'
43
+ }]);
44
+
45
+ if (initialChoice.action === 'analytics') {
46
+ console.log(chalk.blue('📊 Launching Claude Code Analytics Dashboard...'));
47
+ await runAnalytics({});
48
+ return;
49
+ }
50
+
51
+ if (initialChoice.action === 'health') {
52
+ console.log(chalk.blue('🔍 Running Health Check...'));
53
+ const healthResult = await runHealthCheck();
54
+ if (healthResult.runSetup) {
55
+ console.log(chalk.blue('⚙️ Starting Project Setup...'));
56
+ // Continue with setup flow
57
+ return await createClaudeConfig({});
58
+ } else {
59
+ console.log(chalk.green('👍 Health check completed. Returning to main menu...'));
60
+ return await showMainMenu();
61
+ }
62
+ }
63
+
64
+ // Continue with setup if user chose 'setup'
65
+ console.log(chalk.blue('⚙️ Setting up Claude Code configuration...'));
66
+ return await createClaudeConfig({ setupFromMenu: true });
67
+ }
15
68
 
16
69
  async function createClaudeConfig(options = {}) {
17
70
  const targetDir = options.directory || process.cwd();
@@ -40,38 +93,22 @@ async function createClaudeConfig(options = {}) {
40
93
  return;
41
94
  }
42
95
 
43
- // Add initial choice prompt (only if no specific options are provided)
44
- if (!options.yes && !options.language && !options.framework && !options.dryRun) {
45
- console.log(chalk.blue('🚀 Welcome to Claude Code Templates!'));
46
- console.log('');
47
-
48
- const initialChoice = await inquirer.prompt([{
49
- type: 'list',
50
- name: 'action',
51
- message: 'What would you like to do?',
52
- choices: [
53
- {
54
- name: '📊 Analytics Dashboard - Monitor your Claude Code usage and sessions',
55
- value: 'analytics',
56
- short: 'Analytics Dashboard'
57
- },
58
- {
59
- name: '⚙️ Project Setup - Configure Claude Code for your project',
60
- value: 'setup',
61
- short: 'Project Setup'
62
- }
63
- ],
64
- default: 'analytics'
65
- }]);
66
-
67
- if (initialChoice.action === 'analytics') {
68
- console.log(chalk.blue('📊 Launching Claude Code Analytics Dashboard...'));
69
- await runAnalytics(options);
70
- return;
96
+ // Handle health check
97
+ let shouldRunSetup = false;
98
+ if (options.healthCheck || options.health || options.check || options.verify) {
99
+ const healthResult = await runHealthCheck();
100
+ if (healthResult.runSetup) {
101
+ console.log(chalk.blue('⚙️ Starting Project Setup...'));
102
+ shouldRunSetup = true;
103
+ } else {
104
+ console.log(chalk.green('👍 Health check completed. Returning to main menu...'));
105
+ return await showMainMenu();
71
106
  }
72
-
73
- // Continue with setup if user chose 'setup'
74
- console.log(chalk.blue('⚙️ Setting up Claude Code configuration...'));
107
+ }
108
+
109
+ // Add initial choice prompt (only if no specific options are provided and not continuing from health check or menu)
110
+ if (!shouldRunSetup && !options.setupFromMenu && !options.yes && !options.language && !options.framework && !options.dryRun) {
111
+ return await showMainMenu();
75
112
  } else {
76
113
  console.log(chalk.blue('🚀 Setting up Claude Code configuration...'));
77
114
  }
@@ -186,4 +223,4 @@ async function createClaudeConfig(options = {}) {
186
223
  }
187
224
  }
188
225
 
189
- module.exports = createClaudeConfig;
226
+ module.exports = { createClaudeConfig, showMainMenu };