package-installer-cli 1.3.1 → 1.3.3

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: e6be7c9e887c130bca12178ca5b9c3814be6d872a43bd2f6889b0bc2b74611c3
4
- data.tar.gz: 6c470b578f019a6753dd8a0a15050a2321f68d44ec18e4d911c9ec3648f177f1
3
+ metadata.gz: 87cf10ca48c5f33ea24bb36427427bdf709be32b8b654e295b2768bd3077d940
4
+ data.tar.gz: f93337632294f53991e374fd94d42c4c66409292b523370e4de687a2de0f48e3
5
5
  SHA512:
6
- metadata.gz: 3b56770128ea4abf8e2e67a5a9e45fcb460993e89477bf3c919c257436471be2a2df6dac5bc61cd89abfb77ca749af3cbe1adbd79d9d0a38d5cf0d17c11f004a
7
- data.tar.gz: b05634c35e45ada304be549c392ea71dba86a44bafef8d1c6c5c3e3b71a4964138473f1a1517e3f9ec6c8f4cc45c19c5293422183462334d1c6971c62667c12a
6
+ metadata.gz: 3be6855632ef33fd77e69488336a2d276b1c446cea2f422d0b8d02de30cd7dc687141067b864fc10babccd6c86294e43481d2d55bd4bf52db17a82b69ec15415
7
+ data.tar.gz: 73a4b812134e0a256d9bb9c9735da36531c549c672b967f09950645cc72438138b698b90ca5b83a687664a56be1be73301c6e4a989b9064675c39379370856ff
@@ -2,7 +2,6 @@ import { exec } from 'child_process';
2
2
  import { promisify } from 'util';
3
3
  import chalk from 'chalk';
4
4
  import ora from 'ora';
5
- import boxen from 'boxen';
6
5
  import fs from 'fs-extra';
7
6
  import path from 'path';
8
7
  import semver from 'semver';
@@ -32,6 +31,14 @@ const PROJECT_TYPES = getSupportedLanguages().map(lang => {
32
31
  registryUrl = 'https://pypi.org';
33
32
  packageInfoUrl = (packageName) => `https://pypi.org/pypi/${packageName}/json`;
34
33
  break;
34
+ case 'ruby':
35
+ registryUrl = 'https://rubygems.org';
36
+ packageInfoUrl = (packageName) => `https://rubygems.org/api/v1/gems/${packageName}.json`;
37
+ break;
38
+ case 'go':
39
+ registryUrl = 'https://proxy.golang.org';
40
+ packageInfoUrl = (packageName) => `https://proxy.golang.org/${packageName}/@v/list`;
41
+ break;
35
42
  default:
36
43
  // For unsupported languages, we'll try npm registry as fallback
37
44
  registryUrl = 'https://registry.npmjs.org';
@@ -394,11 +401,11 @@ export function showCheckHelp() {
394
401
  {
395
402
  title: 'Supported Package Managers',
396
403
  items: [
397
- 'npm, pnpm, yarn (Node.js)',
404
+ 'npm, pnpm, yarn (JavaScript/TypeScript)',
398
405
  'pip, pipenv, poetry (Python)',
399
406
  'cargo (Rust)',
400
407
  'go modules (Go)',
401
- 'composer (PHP)'
408
+ 'gem, bundler (Ruby)'
402
409
  ]
403
410
  }
404
411
  ],
@@ -461,7 +468,36 @@ async function checkSinglePackage(packageName, verbose = false) {
461
468
  async function checkProjectPackages(verbose = false) {
462
469
  const spinner = ora('Analyzing project dependencies...').start();
463
470
  try {
464
- let projectType = await detectProjectType();
471
+ // Detect ALL project types instead of just one
472
+ const allProjectTypes = await detectAllProjectTypes();
473
+ if (allProjectTypes.length === 0) {
474
+ spinner.fail(chalk.hex('#ff4757')('❌ No supported project configuration files found'));
475
+ console.log(chalk.hex('#95afc0')('💡 Supported files: package.json, tsconfig.json, Cargo.toml, requirements.txt, pyproject.toml, go.mod, Gemfile'));
476
+ return;
477
+ }
478
+ spinner.succeed(chalk.hex('#10ac84')(`✅ Detected ${allProjectTypes.length} project type(s): ${allProjectTypes.map(pt => pt.name).join(', ')}`));
479
+ // Process each project type separately
480
+ for (let i = 0; i < allProjectTypes.length; i++) {
481
+ const projectType = allProjectTypes[i];
482
+ const isMultiProject = allProjectTypes.length > 1;
483
+ if (isMultiProject) {
484
+ console.log('\n' + chalk.hex('#667eea')('═'.repeat(80)));
485
+ console.log(chalk.hex('#667eea')(`📋 Analyzing ${projectType.name} Dependencies (${i + 1}/${allProjectTypes.length})`));
486
+ console.log(chalk.hex('#667eea')('═'.repeat(80)));
487
+ }
488
+ await analyzeSingleProjectType(projectType, verbose, isMultiProject);
489
+ }
490
+ return; // Exit early since we've processed all project types
491
+ }
492
+ catch (error) {
493
+ spinner.fail(chalk.hex('#ff4757')(`❌ Failed to analyze projects: ${error.message}`));
494
+ throw error;
495
+ }
496
+ }
497
+ // New function to analyze a single project type
498
+ async function analyzeSingleProjectType(projectType, verbose, isMultiProject = false) {
499
+ const spinner = ora(`Analyzing ${projectType.name} dependencies...`).start();
500
+ try {
465
501
  let dependencies = {};
466
502
  if (!projectType) {
467
503
  spinner.warn('No supported project files found in current directory');
@@ -472,10 +508,8 @@ async function checkProjectPackages(verbose = false) {
472
508
  console.log(chalk.gray('\n Or specify a package name: pi check <package-name>'));
473
509
  return;
474
510
  }
475
- // Get fresh dependencies if not cached or cache is incomplete
476
- if (Object.keys(dependencies).length === 0) {
477
- dependencies = await getDependenciesForProject(projectType);
478
- }
511
+ // Get fresh dependencies
512
+ dependencies = await getDependenciesForProject(projectType);
479
513
  if (Object.keys(dependencies).length === 0) {
480
514
  spinner.warn(`No dependencies found in ${projectType.name} project`);
481
515
  return;
@@ -486,77 +520,73 @@ async function checkProjectPackages(verbose = false) {
486
520
  try {
487
521
  const info = await getEnhancedPackageInfo(name, version, projectType);
488
522
  packageInfos.push(info);
523
+ spinner.text = `✔ Retrieved info for ${name}`;
489
524
  }
490
525
  catch (error) {
491
526
  console.warn(`⚠️ Could not check ${name}`);
492
527
  }
493
528
  }
494
- spinner.succeed(`Checked ${packageInfos.length} ${projectType.name} packages`);
495
- // Cache the package check results
496
- await cachePackageCheckResults(packageInfos, projectType);
497
- displayPackageInfo(packageInfos, projectType, verbose);
529
+ spinner.succeed(`✔ Checked ${packageInfos.length} ${projectType.name} packages`);
530
+ // Cache the package check results (optional)
531
+ try {
532
+ await cachePackageCheckResults?.(packageInfos, projectType);
533
+ }
534
+ catch (error) {
535
+ // Caching is optional, continue without it
536
+ }
537
+ displayPackageInfo(packageInfos, projectType, verbose, isMultiProject);
498
538
  }
499
539
  catch (error) {
500
- spinner.fail('Failed to analyze project dependencies');
540
+ spinner.fail(`Failed to analyze ${projectType.name} dependencies`);
501
541
  throw error;
502
542
  }
503
543
  }
504
- async function detectProjectType() {
505
- console.log(chalk.gray('🔍 Detecting project type...'));
506
- // Priority order for detection - check most common files first
507
- const priorityFiles = ['package.json', 'Cargo.toml', 'requirements.txt', 'composer.json', 'go.mod'];
508
- // First pass: check priority files in current directory
544
+ // New function to detect ALL project types in a directory
545
+ async function detectAllProjectTypes() {
546
+ console.log(chalk.gray('🔍 Detecting all project types...'));
547
+ const foundTypes = [];
548
+ const foundFiles = [];
549
+ // Priority order for detection - check most common files first (supported languages only)
550
+ const priorityFiles = ['package.json', 'tsconfig.json', 'Cargo.toml', 'requirements.txt', 'pyproject.toml', 'go.mod', 'Gemfile'];
551
+ // Check all priority files in current directory
509
552
  for (const priorityFile of priorityFiles) {
510
553
  const filePath = path.join(process.cwd(), priorityFile);
511
- console.log(chalk.gray(` Checking priority file: ${filePath}`));
554
+ console.log(chalk.gray(` Checking: ${filePath}`));
512
555
  if (await fs.pathExists(filePath)) {
513
556
  console.log(chalk.green(` ✅ Found: ${priorityFile}`));
557
+ foundFiles.push(priorityFile);
514
558
  // Find the project type that matches this file
515
559
  const matchingType = PROJECT_TYPES.find(type => type.files.includes(priorityFile));
516
- if (matchingType) {
560
+ if (matchingType && !foundTypes.find(t => t.name === matchingType.name)) {
517
561
  console.log(chalk.green(` 📦 Detected: ${matchingType.name}`));
518
- return matchingType;
562
+ foundTypes.push(matchingType);
519
563
  }
520
564
  }
521
565
  }
522
- // Second pass: check all other files
566
+ // Check for additional files in each detected project type
523
567
  for (const projectType of PROJECT_TYPES) {
524
- console.log(chalk.gray(` Checking ${projectType.name}: ${projectType.files.join(', ')}`));
568
+ if (foundTypes.find(t => t.name === projectType.name))
569
+ continue; // Already found
525
570
  for (const file of projectType.files) {
526
571
  if (priorityFiles.includes(file))
527
572
  continue; // Already checked
528
- // Check in current directory first
529
573
  const filePath = path.join(process.cwd(), file);
530
574
  if (await fs.pathExists(filePath)) {
531
- console.log(chalk.green(` ✅ Found: ${file}`));
532
- return projectType;
533
- }
534
- }
535
- }
536
- // Third pass: check subdirectories
537
- try {
538
- const currentDirContents = await fs.readdir(process.cwd());
539
- for (const item of currentDirContents) {
540
- const itemPath = path.join(process.cwd(), item);
541
- const stats = await fs.stat(itemPath);
542
- if (stats.isDirectory()) {
543
- for (const priorityFile of priorityFiles) {
544
- const configPath = path.join(itemPath, priorityFile);
545
- if (await fs.pathExists(configPath)) {
546
- console.log(chalk.green(` ✅ Found in subdirectory: ${item}/${priorityFile}`));
547
- const matchingType = PROJECT_TYPES.find(type => type.files.includes(priorityFile));
548
- if (matchingType)
549
- return matchingType;
550
- }
575
+ console.log(chalk.green(` ✅ Found additional: ${file}`));
576
+ foundFiles.push(file);
577
+ if (!foundTypes.find(t => t.name === projectType.name)) {
578
+ console.log(chalk.green(` 📦 Detected: ${projectType.name}`));
579
+ foundTypes.push(projectType);
551
580
  }
552
581
  }
553
582
  }
554
583
  }
555
- catch (error) {
556
- console.log(chalk.yellow(' Warning: Could not read directory contents'));
557
- }
558
- console.log(chalk.yellow(' No project type detected'));
559
- return null;
584
+ return foundTypes;
585
+ }
586
+ async function detectProjectType() {
587
+ // This function now uses detectAllProjectTypes and returns the first one for backward compatibility
588
+ const allTypes = await detectAllProjectTypes();
589
+ return allTypes.length > 0 ? allTypes[0] : null;
560
590
  }
561
591
  async function getDependenciesForProject(projectType) {
562
592
  console.log(chalk.gray(`📋 Looking for dependencies in ${projectType.name} project...`));
@@ -691,8 +721,8 @@ async function getPackageInfo(packageName, currentVersion, projectType) {
691
721
  try {
692
722
  // Clean up version string (remove ^ ~ and similar prefixes)
693
723
  const cleanCurrentVersion = currentVersion?.replace(/[\^~>=<]/, '') || 'unknown';
694
- // Enhanced NPM registry support
695
- if (type.name === 'Node.js') {
724
+ // Enhanced NPM registry support
725
+ if (type.name === 'JavaScript' || type.name === 'TypeScript') {
696
726
  const response = await fetch(`https://registry.npmjs.org/${packageName}`);
697
727
  if (!response.ok) {
698
728
  throw new Error(`Package ${packageName} not found in NPM registry`);
@@ -801,101 +831,95 @@ async function getPackageInfo(packageName, currentVersion, projectType) {
801
831
  throw new Error(`Failed to fetch info for ${packageName}: ${error.message}`);
802
832
  }
803
833
  }
804
- function displayPackageInfo(packages, projectType, verbose = false) {
834
+ function displayPackageInfo(packages, projectType, verbose = false, isMultiProject = false) {
805
835
  if (packages.length === 0) {
806
836
  console.log(chalk.yellow('📦 No packages to display'));
807
837
  return;
808
838
  }
809
- console.log('\n' + chalk.hex('#00d2d3')('📊 Package Analysis Results'));
810
- console.log(chalk.gray('─'.repeat(60)));
811
839
  const outdatedPackages = packages.filter(pkg => pkg.needsUpdate);
812
840
  const deprecatedPackages = packages.filter(pkg => pkg.isDeprecated);
813
841
  const upToDatePackages = packages.filter(pkg => !pkg.needsUpdate && !pkg.isDeprecated);
814
- // Enhanced Summary with statistics
815
- console.log(`\n${chalk.hex('#10ac84')(' Total packages checked:')} ${chalk.bold(packages.length.toString())}`);
816
- console.log(`${chalk.hex('#10ac84')('✅ Up to date:')} ${chalk.bold(upToDatePackages.length.toString())}`);
817
- if (outdatedPackages.length > 0) {
818
- console.log(`${chalk.hex('#f39c12')('⚠️ Packages needing updates:')} ${chalk.bold(outdatedPackages.length.toString())}`);
819
- }
820
- if (deprecatedPackages.length > 0) {
821
- console.log(`${chalk.hex('#ff4757')('🚨 Deprecated packages:')} ${chalk.bold(deprecatedPackages.length.toString())}`);
822
- }
823
- // Show severity breakdown
842
+ // Compact summary header
843
+ console.log('\n' + chalk.hex('#00d2d3')('📊 Package Analysis Results'));
844
+ console.log(chalk.gray(''.repeat(80)));
845
+ const summary = [
846
+ `${chalk.hex('#10ac84')('')} ${upToDatePackages.length} up-to-date`,
847
+ outdatedPackages.length > 0 ? `${chalk.hex('#f39c12')('⚠️')} ${outdatedPackages.length} need updates` : null,
848
+ deprecatedPackages.length > 0 ? `${chalk.hex('#ff4757')('🚨')} ${deprecatedPackages.length} deprecated` : null
849
+ ].filter(Boolean).join('');
850
+ console.log(`${chalk.bold(`Total: ${packages.length}`)} • ${summary}`);
824
851
  if (projectType) {
825
- console.log(`\n${chalk.hex('#00d2d3')('📋 Project Type:')} ${chalk.bold(projectType.name)} (${chalk.cyan(projectType.packageManager)})`);
826
- }
827
- // Determine how many packages to show based on verbose flag
828
- const packagesToShow = verbose ? packages : packages.slice(0, 8);
829
- if (verbose && packages.length > 8) {
830
- console.log(`\n${chalk.hex('#f39c12')('📋 Showing all')} ${chalk.bold(packages.length.toString())} ${chalk.hex('#f39c12')('packages (verbose mode)')}`);
831
- }
832
- else if (!verbose && packages.length > 8) {
833
- console.log(`\n${chalk.hex('#f39c12')('📋 Showing first')} ${chalk.bold('8')} ${chalk.hex('#f39c12')('packages (use --verbose to see all)')}`);
834
- }
835
- packagesToShow.forEach((pkg, index) => {
836
- const statusIcon = pkg.isDeprecated ? '🚨' : pkg.needsUpdate ? '⚠️' : '✅';
837
- const statusColor = pkg.isDeprecated ? '#ff4757' : pkg.needsUpdate ? '#f39c12' : '#10ac84';
838
- const statusText = pkg.isDeprecated ? 'DEPRECATED' : pkg.needsUpdate ? 'UPDATE AVAILABLE' : 'UP TO DATE';
839
- const versionComparison = pkg.currentVersion !== 'unknown' && pkg.latestVersion !== 'unknown'
840
- ? ` ${chalk.gray('')} ${chalk.hex('#10ac84')(pkg.latestVersion)}`
841
- : '';
842
- console.log('\n' + boxen(`${statusIcon} ${chalk.bold(pkg.name)} ${chalk.hex(statusColor)(`[${statusText}]`)}\n` +
843
- `${chalk.gray('Current:')} ${chalk.yellow(pkg.currentVersion)}${versionComparison}\n` +
844
- `${chalk.gray('Type:')} ${chalk.blue(pkg.projectType)} ${chalk.gray('via')} ${chalk.cyan(pkg.packageManager)}\n` +
845
- (pkg.description ? `${chalk.gray('Description:')} ${pkg.description.slice(0, 70)}${pkg.description.length > 70 ? '...' : ''}\n` : '') +
846
- (pkg.homepage ? `${chalk.gray('Homepage:')} ${chalk.blue(pkg.homepage)}\n` : '') +
847
- (pkg.isDeprecated ? `${chalk.hex('#ff4757')('⚠️ DEPRECATED:')} ${pkg.deprecatedMessage || 'This package is no longer maintained'}\n` : '') +
848
- (pkg.alternatives && pkg.alternatives.length > 0 ? `${chalk.gray('Alternatives:')} ${pkg.alternatives.join(', ')}\n` : ''), {
849
- padding: 1,
850
- margin: 0,
851
- borderStyle: 'round',
852
- borderColor: statusColor,
853
- title: `Package ${index + 1}/${packagesToShow.length}`,
854
- titleAlignment: 'left'
855
- }));
856
- });
857
- // Show remaining packages info when not in verbose mode
858
- if (!verbose && packages.length > 8) {
859
- const remaining = packages.length - 8;
860
- const remainingOutdated = packages.slice(8).filter(pkg => pkg.needsUpdate).length;
861
- const remainingDeprecated = packages.slice(8).filter(pkg => pkg.isDeprecated).length;
862
- const remainingUpToDate = packages.slice(8).filter(pkg => !pkg.needsUpdate && !pkg.isDeprecated).length;
863
- console.log('\n' + chalk.hex('#f39c12')(`📦 Remaining ${remaining} packages:`));
864
- console.log(chalk.gray(''.repeat(30)));
865
- if (remainingUpToDate > 0) {
866
- console.log(` ${chalk.hex('#10ac84')('✅')} ${remainingUpToDate} up to date`);
852
+ console.log(`${chalk.hex('#00d2d3')('📋')} ${projectType.name} (${chalk.cyan(projectType.packageManager)})`);
853
+ }
854
+ // Determine how many packages to show
855
+ const packagesToShow = verbose ? packages : packages.slice(0, 12);
856
+ // Group packages by status for better organization
857
+ const groupedPackages = [
858
+ ...deprecatedPackages.slice(0, verbose ? deprecatedPackages.length : 3),
859
+ ...outdatedPackages.slice(0, verbose ? outdatedPackages.length : 8),
860
+ ...upToDatePackages.slice(0, verbose ? upToDatePackages.length : 6)
861
+ ].slice(0, verbose ? packages.length : 12);
862
+ if (groupedPackages.length > 0) {
863
+ console.log('\n');
864
+ // Compact table format
865
+ groupedPackages.forEach((pkg, index) => {
866
+ const statusIcon = pkg.isDeprecated ? '🚨' : pkg.needsUpdate ? '⚠️' : '✅';
867
+ const statusColor = pkg.isDeprecated ? '#ff4757' : pkg.needsUpdate ? '#f39c12' : '#10ac84';
868
+ // Format version comparison compactly
869
+ const versionText = pkg.needsUpdate && pkg.latestVersion !== 'unknown'
870
+ ? `${chalk.dim(pkg.currentVersion)} ${chalk.hex(statusColor)(pkg.latestVersion)}`
871
+ : chalk.dim(pkg.currentVersion);
872
+ // Truncate name and description for compact view
873
+ const name = pkg.name.length > 25 ? pkg.name.slice(0, 22) + '...' : pkg.name;
874
+ const desc = pkg.description
875
+ ? (pkg.description.length > 50 ? pkg.description.slice(0, 47) + '...' : pkg.description)
876
+ : chalk.dim('No description');
877
+ console.log(`${statusIcon} ${chalk.bold(name.padEnd(25))} ${versionText.padEnd(20)} ${chalk.gray(desc)}`);
878
+ // Show deprecation warning inline
879
+ if (pkg.isDeprecated && pkg.deprecatedMessage) {
880
+ console.log(` ${chalk.hex('#ff4757')('⚠️')} ${chalk.dim(pkg.deprecatedMessage.slice(0, 80))}`);
881
+ }
882
+ });
883
+ }
884
+ // Show remaining packages summary when not in verbose mode
885
+ if (!verbose && packages.length > 12) {
886
+ const remaining = packages.length - groupedPackages.length;
887
+ const remainingOutdated = packages.filter(pkg => pkg.needsUpdate && !groupedPackages.includes(pkg)).length;
888
+ const remainingUpToDate = packages.filter(pkg => !pkg.needsUpdate && !pkg.isDeprecated && !groupedPackages.includes(pkg)).length;
889
+ console.log('\n' + chalk.gray('─'.repeat(80)));
890
+ const hiddenSummary = [
891
+ remainingUpToDate > 0 ? `${chalk.hex('#10ac84')('✅')} ${remainingUpToDate} more up-to-date` : null,
892
+ remainingOutdated > 0 ? `${chalk.hex('#f39c12')('⚠️')} ${remainingOutdated} more need updates` : null
893
+ ].filter(Boolean).join('');
894
+ if (hiddenSummary) {
895
+ console.log(`${chalk.dim(`+${remaining} hidden:`)} ${hiddenSummary}`);
867
896
  }
897
+ // Show sample of remaining package names
868
898
  if (remainingOutdated > 0) {
869
- console.log(` ${chalk.hex('#f39c12')('⚠️')} ${remainingOutdated} need updates`);
870
- // Show names of remaining outdated packages
871
- const outdatedNames = packages.slice(8).filter(pkg => pkg.needsUpdate).slice(0, 5).map(pkg => pkg.name);
872
- console.log(` ${chalk.gray('Packages:')} ${outdatedNames.join(', ')}${outdatedNames.length < remainingOutdated ? '...' : ''}`);
899
+ const sampleNames = packages.filter(pkg => pkg.needsUpdate && !groupedPackages.includes(pkg))
900
+ .slice(0, 4).map(pkg => pkg.name).join(', ');
901
+ console.log(`${chalk.dim('Outdated:')} ${sampleNames}${remainingOutdated > 4 ? '...' : ''}`);
873
902
  }
874
- if (remainingDeprecated > 0) {
875
- console.log(` ${chalk.hex('#ff4757')('🚨')} ${remainingDeprecated} deprecated`);
876
- // Show names of remaining deprecated packages
877
- const deprecatedNames = packages.slice(8).filter(pkg => pkg.isDeprecated).slice(0, 3).map(pkg => pkg.name);
878
- console.log(` ${chalk.gray('Packages:')} ${deprecatedNames.join(', ')}${deprecatedNames.length < remainingDeprecated ? '...' : ''}`);
903
+ console.log(`\n${chalk.cyan('💡')} Use ${chalk.bold('--verbose')} to see all ${packages.length} packages`);
904
+ }
905
+ // Compact recommendations section
906
+ if (outdatedPackages.length > 0 || deprecatedPackages.length > 0) {
907
+ console.log('\n' + chalk.hex('#667eea')('💡 Quick Actions:'));
908
+ console.log(chalk.gray('─'.repeat(40)));
909
+ if (deprecatedPackages.length > 0) {
910
+ console.log(`${chalk.hex('#ff4757')('🚨')} ${deprecatedPackages.length} deprecated - replace immediately`);
911
+ deprecatedPackages.slice(0, 3).forEach(pkg => {
912
+ console.log(` • ${chalk.red(pkg.name)} ${chalk.gray(pkg.deprecatedMessage ? '- ' + pkg.deprecatedMessage.slice(0, 50) + '...' : '')}`);
913
+ });
914
+ }
915
+ if (outdatedPackages.length > 0 && projectType) {
916
+ console.log(`${chalk.hex('#f39c12')('⚠️')} ${outdatedPackages.length} need updates - Run: ${chalk.cyan(projectType.getUpdateCommand())}`);
917
+ }
918
+ if (packages.length > 50) {
919
+ console.log(`${chalk.hex('#95afc0')('📦')} Large dependency count (${packages.length}) - consider optimization`);
879
920
  }
880
- console.log(`\n ${chalk.cyan('💡 Tip:')} Use ${chalk.bold('--verbose')} to see detailed info for all ${packages.length} packages`);
881
- }
882
- // Enhanced recommendations section
883
- console.log('\n' + chalk.hex('#00d2d3')('💡 Recommendations:'));
884
- console.log(chalk.gray('─'.repeat(30)));
885
- if (deprecatedPackages.length > 0) {
886
- console.log(`${chalk.hex('#ff4757')('🚨 URGENT:')} Replace ${deprecatedPackages.length} deprecated package(s) immediately`);
887
- deprecatedPackages.slice(0, 3).forEach(pkg => {
888
- console.log(` • ${chalk.red(pkg.name)} ${chalk.gray(pkg.deprecatedMessage ? '- ' + pkg.deprecatedMessage.slice(0, 50) + '...' : '')}`);
889
- });
890
- }
891
- if (outdatedPackages.length > 0 && projectType) {
892
- console.log(`${chalk.hex('#f39c12')('⚠️ UPDATE:')} ${outdatedPackages.length} package(s) need updating`);
893
- console.log(` Run: ${chalk.cyan(projectType.getUpdateCommand())}`);
894
- }
895
- if (packages.length > 50) {
896
- console.log(`${chalk.hex('#95afc0')('📦 INFO:')} Large dependency count (${packages.length}) - consider reviewing for optimization`);
897
921
  }
898
- console.log(chalk.gray(`\n Last checked: ${new Date().toLocaleString()}`));
922
+ console.log(chalk.gray(`\nLast checked: ${new Date().toLocaleString()}`));
899
923
  }
900
924
  /**
901
925
  * Cache package check results for performance
@@ -872,35 +872,6 @@ export const ENHANCED_LANGUAGE_CONFIGS = {
872
872
  ]
873
873
  }
874
874
  },
875
- // Continue with other languages - abbreviated for space
876
- nodejs: {
877
- name: 'nodejs',
878
- displayName: 'Node.js',
879
- description: 'JavaScript runtime built on Chrome\'s V8 engine',
880
- icon: '💚',
881
- category: 'web',
882
- maturity: 'stable',
883
- packageManagers: [],
884
- configFiles: [],
885
- buildFiles: [],
886
- sourceFileExtensions: ['.js', '.mjs'],
887
- frameworkDetection: [],
888
- toolchain: {
889
- interpreter: { name: 'Node.js', command: 'node', optional: false, description: 'JavaScript runtime' }
890
- },
891
- ecosystem: {
892
- registry: { name: 'npm', url: 'https://npmjs.com' },
893
- community: { github: { repos: 0, stars: 0 }, stackoverflow: { questions: 0, activity: 'high' } },
894
- learning: [],
895
- trends: { githubStars: 0, stackoverflowQuestions: 0, jobPostings: 0, trendDirection: 'stable' }
896
- },
897
- compatibility: {
898
- operatingSystems: ['windows', 'macos', 'linux'],
899
- architectures: ['x64', 'arm64'],
900
- containers: true,
901
- cloud: []
902
- }
903
- },
904
875
  go: {
905
876
  name: 'go',
906
877
  displayName: 'Go',
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: package-installer-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - sharique
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-09-30 00:00:00.000000000 Z
11
+ date: 2025-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler