package-installer-cli 1.2.0 → 1.3.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7f432378951e281eb37210295d7894abbf072093bd9a2e6099f1d3219ad45eb0
4
- data.tar.gz: 0e9edf8310281ce583765615d8d41f1897b7e0fab8e6cc3dbbfa405d39a63cc9
3
+ metadata.gz: e6be7c9e887c130bca12178ca5b9c3814be6d872a43bd2f6889b0bc2b74611c3
4
+ data.tar.gz: 6c470b578f019a6753dd8a0a15050a2321f68d44ec18e4d911c9ec3648f177f1
5
5
  SHA512:
6
- metadata.gz: b0490199b16d2f27b1513fc9360895c02cb9a1a2fc58a4cddc5611c20afa21c8ef6e609d99b4dc7271a19de0ea21c1275127839d4b56b26b91e0554cff66c296
7
- data.tar.gz: 6e7cec10cae328695c8fb9328797f5efc46ced7e04b0bb99dffe40ccbb887bc9ee495277b2ac49e5196e88f98e6a71a2cec823ad4ec692ee78424ce5cc3b5d53
6
+ metadata.gz: 3b56770128ea4abf8e2e67a5a9e45fcb460993e89477bf3c919c257436471be2a2df6dac5bc61cd89abfb77ca749af3cbe1adbd79d9d0a38d5cf0d17c11f004a
7
+ data.tar.gz: b05634c35e45ada304be549c392ea71dba86a44bafef8d1c6c5c3e3b71a4964138473f1a1517e3f9ec6c8f4cc45c19c5293422183462334d1c6971c62667c12a
data/CHANGELOG.md CHANGED
@@ -5,7 +5,7 @@ All notable changes to the Package Installer CLI Ruby gem will be documented in
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [1.1.0] - 2025-09-23
8
+ ## [1.3.0] - 2025-09-23
9
9
 
10
10
  ### Updated
11
11
  - Version bump to 1.1.0
data/dist/commands/add.js CHANGED
@@ -4,10 +4,12 @@ import gradient from 'gradient-string';
4
4
  import boxen from 'boxen';
5
5
  import path from 'path';
6
6
  import fs from 'fs-extra';
7
- import { addFeature, detectProjectStack, SUPPORTED_FEATURES } from '../utils/featureInstaller.js';
7
+ import { createStandardHelp } from '../utils/helpFormatter.js';
8
+ import { addFeature, detectProjectStack, SUPPORTED_FEATURES, ensureFeaturesLoaded } from '../utils/featureInstaller.js';
8
9
  import { historyManager } from '../utils/historyManager.js';
9
- import { getCachedProject, cacheProjectData } from '../utils/cacheManager.js';
10
+ import { cacheProjectData } from '../utils/cacheManager.js';
10
11
  import { getFeaturesJsonPath, getFeaturesPath } from '../utils/pathResolver.js';
12
+ import { displayCommandBanner } from '../utils/banner.js';
11
13
  /**
12
14
  * Helper function to capitalize strings
13
15
  */
@@ -15,52 +17,95 @@ function capitalize(str) {
15
17
  return str.charAt(0).toUpperCase() + str.slice(1);
16
18
  }
17
19
  /**
18
- * Get features.json configuration
20
+ * Get features.json configuration with new jsonPath structure
19
21
  */
20
- function getFeaturesConfig() {
22
+ // Cache for features config to avoid repeated file reads
23
+ let featuresConfigCache = null;
24
+ async function getFeaturesConfig() {
25
+ // Return cached config if available
26
+ if (featuresConfigCache) {
27
+ return featuresConfigCache;
28
+ }
21
29
  try {
22
30
  // Use the centralized path resolver
23
31
  const featuresPath = getFeaturesJsonPath();
24
32
  if (fs.existsSync(featuresPath)) {
25
- return JSON.parse(fs.readFileSync(featuresPath, 'utf-8'));
33
+ const baseConfig = JSON.parse(fs.readFileSync(featuresPath, 'utf-8'));
34
+ const processedConfig = {};
35
+ // Process each feature to load individual JSON files
36
+ for (const [featureName, config] of Object.entries(baseConfig.features || baseConfig)) {
37
+ const featureConfig = config;
38
+ if (featureConfig.jsonPath) {
39
+ try {
40
+ // Load the individual feature JSON file
41
+ const individualFeaturePath = path.resolve(path.dirname(featuresPath), featureConfig.jsonPath);
42
+ if (fs.existsSync(individualFeaturePath)) {
43
+ const individualFeatureData = JSON.parse(fs.readFileSync(individualFeaturePath, 'utf-8'));
44
+ // Merge the base config with the individual feature data
45
+ processedConfig[featureName] = {
46
+ ...featureConfig,
47
+ files: individualFeatureData.files || individualFeatureData,
48
+ ...individualFeatureData
49
+ };
50
+ }
51
+ else {
52
+ // Silently skip missing files to avoid console spam
53
+ processedConfig[featureName] = featureConfig;
54
+ }
55
+ }
56
+ catch (error) {
57
+ // Silently handle errors to avoid console spam
58
+ processedConfig[featureName] = featureConfig;
59
+ }
60
+ }
61
+ else {
62
+ // Legacy format
63
+ processedConfig[featureName] = featureConfig;
64
+ }
65
+ }
66
+ // Cache the processed config
67
+ featuresConfigCache = { features: processedConfig };
68
+ return featuresConfigCache;
26
69
  }
27
- console.warn(chalk.yellow(`⚠️ features.json not found at: ${featuresPath}`));
28
- return { features: {} };
70
+ // Return empty config without warning to avoid console spam
71
+ featuresConfigCache = { features: {} };
72
+ return featuresConfigCache;
29
73
  }
30
74
  catch (error) {
31
- console.warn(chalk.yellow('⚠️ Error reading features.json, using fallback'));
75
+ // Return fallback config without warning
32
76
  return { features: {} };
33
77
  }
34
78
  }
35
79
  /**
36
80
  * Get available feature categories
37
81
  */
38
- function getAvailableFeatures() {
39
- const config = getFeaturesConfig();
40
- return Object.keys(config);
82
+ export async function getAvailableFeatures() {
83
+ const config = await getFeaturesConfig();
84
+ return Object.keys(config.features || {});
41
85
  }
42
86
  /**
43
87
  * Get sub-features for a category
44
88
  */
45
- function getSubFeatures(category) {
46
- const config = getFeaturesConfig();
47
- const categoryConfig = config[category];
89
+ async function getSubFeatures(category) {
90
+ const config = await getFeaturesConfig();
91
+ const categoryConfig = config.features?.[category];
48
92
  if (!categoryConfig || typeof categoryConfig !== 'object') {
49
93
  return [];
50
94
  }
51
- return Object.keys(categoryConfig);
95
+ return Object.keys(categoryConfig.files || {});
52
96
  }
53
97
  /**
54
98
  * List available features from features.json with descriptions
55
99
  */
56
- function listAvailableFeatures() {
57
- const featuresConfig = getFeaturesConfig();
100
+ async function listAvailableFeatures() {
101
+ await ensureFeaturesLoaded();
102
+ const featuresConfig = await getFeaturesConfig();
58
103
  if (!featuresConfig.features || Object.keys(featuresConfig.features).length === 0) {
59
104
  console.log(chalk.yellow('⚠️ No features found in configuration'));
60
105
  return;
61
106
  }
62
107
  const featuresData = Object.entries(featuresConfig.features).map(([key, config]) => {
63
- const providers = Object.keys(config).filter(k => k !== 'description' && k !== 'supportedFrameworks');
108
+ const providers = config.files ? Object.keys(config.files) : [];
64
109
  const description = config.description || 'No description available';
65
110
  const frameworks = config.supportedFrameworks ? config.supportedFrameworks.join(', ') : 'All frameworks';
66
111
  return {
@@ -234,61 +279,60 @@ function showEnhancedSetupInstructions(feature, provider) {
234
279
  /**
235
280
  * Show help for add command
236
281
  */
237
- export function showAddHelp() {
238
- const piGradient = gradient(['#00c6ff', '#0072ff']);
239
- const featuresConfig = getFeaturesConfig();
282
+ export async function showAddHelp() {
283
+ await ensureFeaturesLoaded();
284
+ const featuresConfig = await getFeaturesConfig();
240
285
  const availableFeatures = Object.keys(featuresConfig.features || {});
241
- console.log('\n' + boxen(piGradient.multiline([
242
- '📦 Package Installer CLI - Add Features',
243
- '',
244
- 'USAGE:',
245
- ' pi add # Interactive feature selection',
246
- ' pi add <feature> # Add feature with provider selection',
247
- ' pi add <feature> <provider> # Add specific feature provider',
248
- ' pi add --list # List all available features',
249
- ' pi add --help # Show this help message',
250
- '',
251
- 'EXAMPLES:',
252
- ' pi add # Show all features in dropdown',
253
- ' pi add auth # Show auth providers dropdown',
254
- ' pi add auth clerk # Add Clerk authentication',
255
- ' pi add aws # Show AWS services dropdown',
256
- ' pi add aws ec2 # Add AWS EC2 integration',
257
- ' pi add ai openai # Add OpenAI integration',
258
- ' pi add database postgres # Add PostgreSQL integration',
259
- ' pi add payment stripe # Add Stripe payment integration',
260
- '',
261
- 'OPTIONS:',
262
- ' -l, --list List all available features',
263
- ' -v, --verbose Show detailed output',
264
- ' -h, --help Show this help message',
265
- '',
266
- `AVAILABLE FEATURES (${availableFeatures.length}):`,
267
- availableFeatures.length > 0
268
- ? availableFeatures.map(feature => ` • ${feature}`).join('\n')
269
- : ' No features configured',
270
- '',
271
- 'SUPPORTED FRAMEWORKS:',
272
- ' • Next.js App Router & Pages Router',
273
- ' React Create React App & Vite',
274
- ' Express.js Node.js backend framework',
275
- ' NestJS TypeScript backend framework',
276
- ' Vue.js Vue 3 with Composition API',
277
- ' Angular Angular 15+',
278
- ' Remix Full-stack React framework',
279
- ' And more coming soon...',
280
- '',
281
- 'NOTES:',
282
- ' • Features are automatically configured for your framework',
283
- ' • Environment variables are added to .env files',
284
- ' TypeScript and JavaScript are both supported',
285
- ' Use "pi add --list" to see detailed feature information'
286
- ].join('\n')), {
287
- padding: 1,
288
- margin: 1,
289
- borderStyle: 'round',
290
- borderColor: 'blue'
291
- }));
286
+ const helpConfig = {
287
+ commandName: 'Add',
288
+ emoji: '',
289
+ description: 'Add new features to your project with automatic framework integration.\nSupports authentication, databases, AI, payments, AWS services, and more.',
290
+ usage: [
291
+ 'add [options]',
292
+ 'add <feature> [provider] [options]'
293
+ ],
294
+ options: [
295
+ { flag: '-l, --list', description: 'List all available features' },
296
+ { flag: '-v, --verbose', description: 'Show detailed output' }
297
+ ],
298
+ examples: [
299
+ { command: 'add', description: 'Interactive feature selection' },
300
+ { command: 'add auth', description: 'Show auth providers dropdown' },
301
+ { command: 'add auth clerk', description: 'Add Clerk authentication' },
302
+ { command: 'add aws ec2', description: 'Add AWS EC2 integration' },
303
+ { command: 'add ai openai', description: 'Add OpenAI integration' },
304
+ { command: 'add database postgres', description: 'Add PostgreSQL integration' },
305
+ { command: 'add payment stripe', description: 'Add Stripe payment integration' },
306
+ { command: 'add --list', description: 'List all available features' }
307
+ ],
308
+ additionalSections: [
309
+ {
310
+ title: `Available Features (${availableFeatures.length})`,
311
+ items: availableFeatures.length > 0
312
+ ? availableFeatures
313
+ : ['No features configured']
314
+ },
315
+ {
316
+ title: 'Supported Frameworks',
317
+ items: [
318
+ 'Next.js - App Router & Pages Router',
319
+ 'React - Create React App & Vite',
320
+ 'Express.js - Node.js backend framework',
321
+ 'NestJS - TypeScript backend framework',
322
+ 'Vue.js - Vue 3 with Composition API',
323
+ 'Angular - Angular 15+',
324
+ 'Remix - Full-stack React framework'
325
+ ]
326
+ }
327
+ ],
328
+ tips: [
329
+ 'Features are automatically configured for your framework',
330
+ 'Environment variables are added to .env files',
331
+ 'TypeScript and JavaScript are both supported',
332
+ 'Use "pi add --list" to see detailed feature information'
333
+ ]
334
+ };
335
+ createStandardHelp(helpConfig);
292
336
  }
293
337
  /**
294
338
  * Main add command handler with enhanced syntax support
@@ -301,21 +345,19 @@ export function showAddHelp() {
301
345
  */
302
346
  export async function addCommand(feature, provider, options = {}) {
303
347
  try {
304
- // Handle help flag
305
- if (options.help || feature === '--help' || feature === '-h') {
306
- showAddHelp();
307
- return;
308
- }
348
+ // Ensure features are loaded first
349
+ await ensureFeaturesLoaded();
309
350
  // Handle list flag
310
351
  if (options.list || feature === '--list' || feature === '-l') {
311
- listAvailableFeatures();
352
+ await listAvailableFeatures();
312
353
  return;
313
354
  }
355
+ // Display command banner
356
+ displayCommandBanner('Add', 'Add new features to your project with integrated templates and configurations');
314
357
  // Initialize history manager
315
358
  await historyManager.init();
316
359
  // Show disclaimer
317
360
  showFeatureDisclaimer();
318
- console.log(chalk.hex('#9c88ff')('\n🔮 Adding features to your project...'));
319
361
  // Use provided project path or current directory
320
362
  const projectPath = options.projectPath || process.cwd();
321
363
  let projectInfo;
@@ -330,7 +372,8 @@ export async function addCommand(feature, provider, options = {}) {
330
372
  }
331
373
  else {
332
374
  // Standalone add command - detect framework from project files
333
- projectInfo = await getCachedProject(projectPath);
375
+ // Get cached project info or detect it (simplified)
376
+ projectInfo = null; // Simplified - always detect fresh
334
377
  if (!projectInfo) {
335
378
  console.log(chalk.yellow('🔍 Analyzing project structure...'));
336
379
  projectInfo = await detectProjectStack(projectPath);
@@ -341,7 +384,7 @@ export async function addCommand(feature, provider, options = {}) {
341
384
  const projectName = await fs.pathExists(packageJsonPath)
342
385
  ? (await fs.readJson(packageJsonPath)).name || path.basename(projectPath)
343
386
  : path.basename(projectPath);
344
- await cacheProjectData(projectPath, projectName, projectInfo.projectLanguage || 'unknown', projectInfo.framework, [], 0);
387
+ await cacheProjectData(projectPath, projectName, projectInfo.projectLanguage || 'unknown');
345
388
  }
346
389
  catch (error) {
347
390
  console.warn(chalk.yellow('⚠️ Could not cache project info'));
@@ -375,8 +418,8 @@ export async function addCommand(feature, provider, options = {}) {
375
418
  console.log(chalk.red('❌ Features configuration not found'));
376
419
  return;
377
420
  }
378
- const featuresConfig = JSON.parse(await fs.readFile(featuresConfigPath, 'utf-8'));
379
- const availableFeatures = Object.keys(featuresConfig.features);
421
+ const featuresConfig = await getFeaturesConfig();
422
+ const availableFeatures = Object.keys(featuresConfig.features || {});
380
423
  // Handle different command syntax cases
381
424
  if (!feature) {
382
425
  // Case 1: "pi add" - Show interactive dropdown for all features
@@ -511,7 +554,7 @@ export async function addCommand(feature, provider, options = {}) {
511
554
  return;
512
555
  }
513
556
  // Get available sub-features/providers
514
- const subFeatures = getSubFeatures(selectedFeature);
557
+ const subFeatures = await getSubFeatures(selectedFeature);
515
558
  // If no provider specified and multiple providers available, show selection
516
559
  if (!selectedProvider && subFeatures.length > 1) {
517
560
  const providerChoices = subFeatures.map((subFeature) => {
@@ -7,46 +7,54 @@ import path from 'path';
7
7
  import os from 'os';
8
8
  import gradientString from 'gradient-string';
9
9
  import boxen from 'boxen';
10
- import { createBanner, displaySystemInfo, displaySuccessMessage } from '../utils/dashboard.js';
10
+ import { createStandardHelp } from '../utils/helpFormatter.js';
11
+ import { displayCommandBanner } from '../utils/banner.js';
12
+ import { displaySystemInfo, displaySuccessMessage } from '../utils/dashboard.js';
11
13
  import { HistoryManager } from '../utils/historyManager.js';
12
14
  /**
13
- * Display help for analyze command
15
+ * Display help for analyze command using standardized format
14
16
  */
15
17
  export function showAnalyzeHelp() {
16
- console.clear();
17
- const helpContent = boxen(gradientString(['#667eea', '#764ba2'])('📊 Package Installer CLI Analytics Help') + '\n\n' +
18
- chalk.white('Display comprehensive CLI usage analytics and project dashboard') + '\n\n' +
19
- chalk.cyan('Usage:') + '\n' +
20
- chalk.white(' pi analyze [options]') + '\n' +
21
- chalk.white(' pi stats [options]') + chalk.gray(' (alias)') + '\n\n' +
22
- chalk.cyan('Description:') + '\n' +
23
- chalk.white(' Interactive dashboard showing Package Installer CLI usage statistics,') + '\n' +
24
- chalk.white(' project analytics, recent activities, and development environment info.') + '\n\n' +
25
- chalk.cyan('Options:') + '\n' +
26
- chalk.white(' --export') + chalk.gray(' Export analytics data to JSON file') + '\n' +
27
- chalk.white(' --reset') + chalk.gray(' Reset analytics history') + '\n' +
28
- chalk.white(' --detailed') + chalk.gray(' Show detailed analytics breakdown') + '\n' +
29
- chalk.white(' -h, --help') + chalk.gray(' Show this help message') + '\n\n' +
30
- chalk.cyan('Features:') + '\n' +
31
- chalk.green(' 📈 Command Usage Stats') + chalk.gray(' Frequency and trends of CLI commands') + '\n' +
32
- chalk.green(' 🚀 Project Analytics') + chalk.gray(' Created projects and framework breakdown') + '\n' +
33
- chalk.green(' 📁 Recent Activity') + chalk.gray(' Last created/modified projects timeline') + '\n' +
34
- chalk.green(' 🎯 Feature Usage') + chalk.gray(' Most used features and integrations') + '\n' +
35
- chalk.green(' ⚙️ Environment Info') + chalk.gray(' Development environment overview') + '\n' +
36
- chalk.green(' 📊 Performance') + chalk.gray(' CLI performance metrics and insights') + '\n\n' +
37
- chalk.cyan('Examples:') + '\n' +
38
- chalk.white(' pi analyze') + chalk.gray(' Show complete analytics dashboard') + '\n' +
39
- chalk.white(' pi analyze --detailed') + chalk.gray(' Show detailed breakdown with more metrics') + '\n' +
40
- chalk.white(' pi analyze --export') + chalk.gray(' Export analytics data to JSON file') + '\n' +
41
- chalk.white(' pi analyze --reset') + chalk.gray(' Clear all analytics history') + '\n\n' +
42
- chalk.yellow('💡 Tip: Analytics data is collected from ~/.package-installer-cli/history.json'), {
43
- padding: 1,
44
- margin: { top: 1, bottom: 1, left: 2, right: 2 },
45
- borderStyle: 'round',
46
- borderColor: 'magenta',
47
- backgroundColor: '#000000'
48
- });
49
- console.log(helpContent);
18
+ const helpConfig = {
19
+ commandName: 'Analyze',
20
+ emoji: '📊',
21
+ description: 'Display comprehensive CLI usage analytics and project dashboard.\nInteractive dashboard showing Package Installer CLI usage statistics, project analytics, recent activities, and development environment info.',
22
+ usage: [
23
+ 'analyze [options]',
24
+ 'stats [options] # alias'
25
+ ],
26
+ options: [
27
+ { flag: '--export', description: 'Export analytics data to JSON file' },
28
+ { flag: '--reset', description: 'Reset analytics history' },
29
+ { flag: '--detailed', description: 'Show detailed analytics breakdown' }
30
+ ],
31
+ examples: [
32
+ { command: 'analyze', description: 'Show complete analytics dashboard' },
33
+ { command: 'analyze --detailed', description: 'Show detailed breakdown with more metrics' },
34
+ { command: 'analyze --export', description: 'Export analytics data to JSON file' },
35
+ { command: 'analyze --reset', description: 'Clear all analytics history' },
36
+ { command: 'stats', description: 'Use alias command' }
37
+ ],
38
+ additionalSections: [
39
+ {
40
+ title: 'Features',
41
+ items: [
42
+ '📈 Command Usage Stats - Frequency and trends of CLI commands',
43
+ '🚀 Project Analytics - Created projects and framework breakdown',
44
+ '📁 Recent Activity - Last created/modified projects timeline',
45
+ '🎯 Feature Usage - Most used features and integrations',
46
+ '⚙️ Environment Info - Development environment overview',
47
+ '📊 Performance - CLI performance metrics and insights'
48
+ ]
49
+ }
50
+ ],
51
+ tips: [
52
+ 'Analytics data is collected from ~/.package-installer-cli/history.json',
53
+ 'Use --export to backup your analytics data',
54
+ 'Use --reset to start fresh analytics tracking'
55
+ ]
56
+ };
57
+ createStandardHelp(helpConfig);
50
58
  }
51
59
  /**
52
60
  * Main analyze command function
@@ -57,7 +65,7 @@ export async function analyzeCommand(options = {}) {
57
65
  showAnalyzeHelp();
58
66
  return;
59
67
  }
60
- createBanner('Package Installer CLI Analytics');
68
+ displayCommandBanner('Analytics', 'Comprehensive project analytics and usage insights');
61
69
  const historyManager = new HistoryManager();
62
70
  try {
63
71
  // Load analytics data from history.json
@@ -7,11 +7,97 @@ import fs from 'fs-extra';
7
7
  import path from 'path';
8
8
  import os from 'os';
9
9
  import ora from 'ora';
10
+ import { createStandardHelp } from '../utils/helpFormatter.js';
10
11
  import { getDirectorySize, getCacheStats, getCacheStatus } from '../utils/cacheManager.js';
12
+ /**
13
+ * Display help for cache command
14
+ */
15
+ export function showCacheHelp() {
16
+ const helpConfig = {
17
+ commandName: 'Cache',
18
+ emoji: '🗄️',
19
+ description: 'Manage CLI cache system for improved performance.\nAutomatically manages cached data for faster operations.',
20
+ usage: [
21
+ 'cache [subcommand] [type]',
22
+ 'cache [options]'
23
+ ],
24
+ options: [
25
+ { flag: '--stats', description: 'Show cache statistics' },
26
+ { flag: '--clear [type]', description: 'Clear cache (optional type)' },
27
+ { flag: '--info', description: 'Show cache information' },
28
+ { flag: '--optimize', description: 'Optimize cache' },
29
+ { flag: '--size', description: 'Show cache size only' }
30
+ ],
31
+ examples: [
32
+ { command: 'cache stats', description: 'Show cache statistics' },
33
+ { command: 'cache --stats', description: 'Show cache statistics (flag)' },
34
+ { command: 'cache clear', description: 'Clear all cache' },
35
+ { command: 'cache clear projects', description: 'Clear specific cache type' },
36
+ { command: 'cache info', description: 'Show cache information' },
37
+ { command: 'cache optimize', description: 'Optimize cache performance' },
38
+ { command: 'cache --size', description: 'Show cache size only' }
39
+ ],
40
+ additionalSections: [
41
+ {
42
+ title: 'Subcommands',
43
+ items: [
44
+ 'stats - Show cache statistics and usage info',
45
+ 'clear [type] - Clear cache (all or specific type)',
46
+ 'info - Show cache configuration and paths',
47
+ 'optimize - Optimize cache performance'
48
+ ]
49
+ },
50
+ {
51
+ title: 'Cache Types',
52
+ items: [
53
+ 'projects - Project metadata and analysis',
54
+ 'analysis - Analysis results and reports',
55
+ 'packages - Package version information',
56
+ 'templates - Template usage statistics',
57
+ 'system - System environment information',
58
+ 'all - Clear all cache types'
59
+ ]
60
+ }
61
+ ],
62
+ tips: [
63
+ 'Cache improves CLI performance by storing frequently used data',
64
+ 'Cache is automatically managed but you can manually optimize it',
65
+ 'Use --size to check cache disk usage before clearing'
66
+ ]
67
+ };
68
+ createStandardHelp(helpConfig);
69
+ }
11
70
  /**
12
71
  * Main cache command function
13
72
  */
14
- export async function cacheCommand(subcommand, type) {
73
+ export async function cacheCommand(subcommand, type, options = {}) {
74
+ // Handle help flag
75
+ if (options.help || options['--help'] || options['-h'] || subcommand === '--help' || subcommand === '-h') {
76
+ showCacheHelp();
77
+ return;
78
+ }
79
+ // Handle option flags
80
+ if (options.stats || subcommand === 'stats') {
81
+ await cacheStatsCommand();
82
+ return;
83
+ }
84
+ if (options.clear !== undefined || subcommand === 'clear') {
85
+ const clearType = options.clear || type;
86
+ await cacheClearCommand(clearType);
87
+ return;
88
+ }
89
+ if (options.info || subcommand === 'info') {
90
+ await cacheInfoCommand();
91
+ return;
92
+ }
93
+ if (options.optimize || subcommand === 'optimize') {
94
+ await cacheOptimizeCommand();
95
+ return;
96
+ }
97
+ if (options.size) {
98
+ await cacheSizeCommand();
99
+ return;
100
+ }
15
101
  // Handle subcommands
16
102
  if (subcommand === 'stats') {
17
103
  await cacheStatsCommand();
@@ -27,26 +113,35 @@ export async function cacheCommand(subcommand, type) {
27
113
  }
28
114
  else {
29
115
  // Default cache command - show help and quick stats
116
+ console.clear();
30
117
  console.log(gradientString(['#00d2d3', '#0084ff'])('🗄️ Cache Manager\n'));
31
118
  console.log(chalk.cyan('Available commands:'));
32
- console.log(chalk.gray(' pi cache stats - Show cache statistics'));
33
- console.log(chalk.gray(' pi cache clear - Clear all cache'));
119
+ console.log(chalk.gray(' pi cache stats - Show cache statistics'));
120
+ console.log(chalk.gray(' pi cache clear - Clear all cache'));
34
121
  console.log(chalk.gray(' pi cache clear <type> - Clear specific cache type'));
35
- console.log(chalk.gray(' pi cache info - Show cache configuration'));
36
- console.log(chalk.gray(' pi cache optimize - Optimize cache performance'));
122
+ console.log(chalk.gray(' pi cache info - Show cache configuration'));
123
+ console.log(chalk.gray(' pi cache optimize - Optimize cache performance'));
124
+ console.log(chalk.gray(' pi cache --help - Show detailed help'));
37
125
  console.log(chalk.cyan('\nCache types:'));
38
- console.log(chalk.gray(' projects, templates, analysis, packages'));
126
+ console.log(chalk.gray(' projects, templates, analysis, packages, system, all'));
39
127
  // Show quick stats
40
128
  try {
41
129
  const stats = getCacheStats();
42
130
  console.log(chalk.cyan('\nQuick Stats:'));
43
131
  console.log(chalk.gray(` Cached Projects: ${stats.projects?.length || 0}`));
44
132
  console.log(chalk.gray(` Template Files: ${stats.templateFiles?.size || Object.keys(stats.templateFiles || {}).length || 0}`));
133
+ // Show cache size
134
+ const cacheDir = path.join(os.homedir(), '.pi-cache');
135
+ if (await fs.pathExists(cacheDir)) {
136
+ const size = await getDirectorySize(cacheDir);
137
+ console.log(chalk.gray(` Cache Size: ${(size / 1024 / 1024).toFixed(2)} MB`));
138
+ }
45
139
  }
46
140
  catch (error) {
47
141
  console.log(chalk.yellow('\n⚠️ Cache not initialized yet'));
48
142
  }
49
143
  console.log(chalk.green('\n✅ Cache system ready'));
144
+ console.log(chalk.gray('💡 Use --help for detailed options'));
50
145
  }
51
146
  }
52
147
  /**
@@ -174,6 +269,46 @@ async function cacheInfoCommand() {
174
269
  console.log(chalk.gray(' • templateFiles - Cached template file contents'));
175
270
  console.log(chalk.gray(' • system - System environment info'));
176
271
  }
272
+ /**
273
+ * Cache size subcommand
274
+ */
275
+ async function cacheSizeCommand() {
276
+ console.log(gradientString(['#00d2d3', '#0084ff'])('\n📊 Cache Size Information\n'));
277
+ const spinner = ora('Calculating cache size...').start();
278
+ try {
279
+ const cacheDir = path.join(os.homedir(), '.pi-cache');
280
+ if (!await fs.pathExists(cacheDir)) {
281
+ spinner.warn('Cache directory not found');
282
+ console.log(chalk.yellow('⚠️ Cache has not been initialized yet'));
283
+ return;
284
+ }
285
+ const totalSize = await getDirectorySize(cacheDir);
286
+ const cacheFile = path.join(cacheDir, 'cache.json');
287
+ spinner.succeed('Cache size calculated');
288
+ console.log(chalk.cyan('📁 Cache Size Breakdown:'));
289
+ console.log(chalk.gray(` Total Cache Size: ${(totalSize / 1024 / 1024).toFixed(2)} MB`));
290
+ if (await fs.pathExists(cacheFile)) {
291
+ const cacheFileStats = await fs.stat(cacheFile);
292
+ console.log(chalk.gray(` Cache Data File: ${(cacheFileStats.size / 1024).toFixed(2)} KB`));
293
+ }
294
+ // Show cache efficiency
295
+ if (totalSize > 50 * 1024 * 1024) { // 50MB
296
+ console.log(chalk.yellow('\n⚠️ Cache is quite large (>50MB)'));
297
+ console.log(chalk.gray('💡 Consider running "pi cache optimize" or "pi cache clear"'));
298
+ }
299
+ else if (totalSize > 10 * 1024 * 1024) { // 10MB
300
+ console.log(chalk.cyan('\n💡 Cache size is reasonable'));
301
+ console.log(chalk.gray('Consider optimizing if performance is slow'));
302
+ }
303
+ else {
304
+ console.log(chalk.green('\n✅ Cache size is optimal'));
305
+ }
306
+ }
307
+ catch (error) {
308
+ spinner.fail('Failed to calculate cache size');
309
+ console.error(chalk.red(`❌ Error: ${error.message}`));
310
+ }
311
+ }
177
312
  /**
178
313
  * Cache optimize subcommand
179
314
  */