package-installer-cli 1.2.0 → 1.3.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.
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Standardized Help Formatter for Package Installer CLI
3
+ * Creates consistent, beautiful help displays for all commands
4
+ */
5
+ import chalk from 'chalk';
6
+ import gradient from 'gradient-string';
7
+ import boxen from 'boxen';
8
+ import { getPackageVersion } from './utils.js';
9
+ /**
10
+ * Create standardized help display for commands
11
+ */
12
+ export function createStandardHelp(config) {
13
+ const version = getPackageVersion();
14
+ const piGradient = gradient(['#00c6ff', '#0072ff']);
15
+ const headerGradient = gradient(['#4facfe', '#00f2fe']);
16
+ let helpContent = '';
17
+ // Header
18
+ helpContent += headerGradient(`${config.emoji} Package Installer CLI - ${config.commandName} Command`) + '\n\n';
19
+ // Description
20
+ helpContent += chalk.white(config.description) + '\n\n';
21
+ // Usage
22
+ helpContent += chalk.cyan('Usage:') + '\n';
23
+ config.usage.forEach(usage => {
24
+ helpContent += chalk.white(` ${piGradient('pi')} ${usage}`) + '\n';
25
+ });
26
+ helpContent += '\n';
27
+ // Options
28
+ if (config.options && config.options.length > 0) {
29
+ helpContent += chalk.cyan('Options:') + '\n';
30
+ config.options.forEach(option => {
31
+ helpContent += chalk.gray(` ${option.flag.padEnd(20)} ${option.description}`) + '\n';
32
+ });
33
+ helpContent += '\n';
34
+ }
35
+ // Examples
36
+ if (config.examples && config.examples.length > 0) {
37
+ helpContent += chalk.cyan('Examples:') + '\n';
38
+ config.examples.forEach(example => {
39
+ // Check if command already starts with 'pi', if not add it
40
+ const command = example.command.startsWith('pi ') ? example.command : `pi ${example.command}`;
41
+ const formattedCommand = command.replace(/^pi /, `${piGradient('pi')} `);
42
+ helpContent += chalk.gray(` ${formattedCommand.padEnd(35)} # ${example.description}`) + '\n';
43
+ });
44
+ helpContent += '\n';
45
+ }
46
+ // Additional sections
47
+ if (config.additionalSections && config.additionalSections.length > 0) {
48
+ config.additionalSections.forEach(section => {
49
+ helpContent += chalk.hex('#00d2d3')(`šŸ’” ${section.title}:`) + '\n';
50
+ section.items.forEach(item => {
51
+ helpContent += chalk.hex('#95afc0')(` • ${item}`) + '\n';
52
+ });
53
+ helpContent += '\n';
54
+ });
55
+ }
56
+ // Tips
57
+ if (config.tips && config.tips.length > 0) {
58
+ config.tips.forEach(tip => {
59
+ helpContent += chalk.yellow(`šŸ’” Tip: ${tip}`) + '\n';
60
+ });
61
+ }
62
+ // Version footer
63
+ helpContent += chalk.hex('#636e72')(`\nšŸ“¦ Package Installer CLI v${version} • Fast • Smart • Feature-Rich`);
64
+ console.log('\n' + boxen(helpContent, {
65
+ padding: 1,
66
+ borderStyle: 'round',
67
+ borderColor: 'cyan',
68
+ backgroundColor: '#0a0a0a'
69
+ }));
70
+ }
71
+ /**
72
+ * Quick help display for commands with minimal options
73
+ */
74
+ export function createQuickHelp(commandName, emoji, description, usage, options) {
75
+ const piGradient = gradient(['#00c6ff', '#0072ff']);
76
+ const headerGradient = gradient(['#4facfe', '#00f2fe']);
77
+ let helpContent = headerGradient(`${emoji} ${commandName.toUpperCase()} COMMAND HELP`) + '\n\n';
78
+ helpContent += chalk.white(description) + '\n\n';
79
+ helpContent += chalk.cyan('Usage:') + '\n';
80
+ helpContent += chalk.white(` ${piGradient('pi')} ${usage}`) + '\n\n';
81
+ if (options.length > 0) {
82
+ helpContent += chalk.cyan('Options:') + '\n';
83
+ options.forEach(option => {
84
+ helpContent += chalk.gray(` ${option}`) + '\n';
85
+ });
86
+ }
87
+ console.log('\n' + boxen(helpContent, {
88
+ padding: 1,
89
+ borderStyle: 'round',
90
+ borderColor: 'cyan',
91
+ backgroundColor: '#0a0a0a'
92
+ }));
93
+ }
94
+ /**
95
+ * Create error help display
96
+ */
97
+ export function createErrorHelp(commandName, error, suggestion) {
98
+ let helpContent = chalk.red(`āŒ ${commandName.toUpperCase()} ERROR`) + '\n\n';
99
+ helpContent += chalk.white(error) + '\n';
100
+ if (suggestion) {
101
+ helpContent += '\n' + chalk.yellow(`šŸ’” Suggestion: ${suggestion}`) + '\n';
102
+ }
103
+ helpContent += '\n' + chalk.gray(`Run: `) + chalk.cyan(`pi ${commandName} --help`) + chalk.gray(` for more information`);
104
+ console.log('\n' + boxen(helpContent, {
105
+ padding: 1,
106
+ borderStyle: 'round',
107
+ borderColor: 'red',
108
+ backgroundColor: '#0a0a0a'
109
+ }));
110
+ }
@@ -25,7 +25,7 @@ export function getCliRootPath() {
25
25
  if (fs.existsSync(packageJsonPath)) {
26
26
  try {
27
27
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
28
- if (packageNames.includes(packageJson.name)) {
28
+ if (packageNames.includes(packageJson.name) && fs.existsSync(path.join(currentDir, 'features'))) {
29
29
  return currentDir;
30
30
  }
31
31
  }
@@ -49,77 +49,51 @@ export function getCliRootPath() {
49
49
  // Continue to other methods
50
50
  }
51
51
  }
52
- // Method 3: Try to resolve using require.resolve for npm installations
52
+ // Method 3: Check current working directory (in case the CLI is run from the project root)
53
+ const cwdPath = process.cwd();
54
+ const workspacePackage = path.join(cwdPath, 'package.json');
55
+ if (fs.existsSync(workspacePackage) && fs.existsSync(path.join(cwdPath, 'features'))) {
56
+ try {
57
+ const packageJson = JSON.parse(fs.readFileSync(workspacePackage, 'utf-8'));
58
+ if (packageNames.includes(packageJson.name)) {
59
+ return cwdPath;
60
+ }
61
+ }
62
+ catch (error) {
63
+ // Continue to other methods
64
+ }
65
+ }
66
+ // Method 4: Try to resolve using require.resolve for npm installations
53
67
  for (const packageName of packageNames) {
54
68
  try {
55
69
  const packageMainPath = require.resolve(`${packageName}/package.json`);
56
- return path.dirname(packageMainPath);
70
+ const resolvedRoot = path.dirname(packageMainPath);
71
+ if (fs.existsSync(path.join(resolvedRoot, 'features'))) {
72
+ return resolvedRoot;
73
+ }
57
74
  }
58
75
  catch (error) {
59
76
  // Package not found in require cache, try next
60
77
  }
61
78
  }
62
- // Method 4: Check common global installation paths for all package managers
79
+ // Method 5: Check common global installation paths for all package managers
63
80
  const globalPaths = [];
81
+ const homeDir = process.env.HOME || process.env.USERPROFILE || '';
64
82
  // npm global paths
65
83
  globalPaths.push(
66
84
  // Linux/macOS npm global paths
67
85
  '/usr/local/lib/node_modules/@0xshariq/package-installer', '/usr/lib/node_modules/@0xshariq/package-installer',
68
86
  // User-specific npm global paths
69
- path.join(process.env.HOME || '', '.npm-global/lib/node_modules/@0xshariq/package-installer'), path.join(process.env.HOME || '', '.npm/lib/node_modules/@0xshariq/package-installer'),
87
+ path.join(homeDir, '.npm-global/lib/node_modules/@0xshariq/package-installer'), path.join(homeDir, '.npm/lib/node_modules/@0xshariq/package-installer'),
70
88
  // Windows npm global paths
71
89
  path.join(process.env.APPDATA || '', 'npm/node_modules/@0xshariq/package-installer'), path.join(process.env.ProgramFiles || '', 'nodejs/node_modules/@0xshariq/package-installer'));
72
- // PyPI/pip global paths
73
- if (process.env.HOME) {
74
- globalPaths.push(
75
- // Linux/macOS pip user install paths
76
- path.join(process.env.HOME, '.local/lib/python*/site-packages/package-installer-cli'), path.join(process.env.HOME, '.local/bin/package-installer-cli'),
77
- // System-wide pip install paths
78
- '/usr/local/lib/python*/site-packages/package-installer-cli', '/usr/lib/python*/site-packages/package-installer-cli');
79
- }
80
- // RubyGems global paths
81
- if (process.env.HOME) {
82
- globalPaths.push(
83
- // User gem installation paths
84
- path.join(process.env.HOME, '.gem/ruby/*/gems/package-installer-cli-*'), path.join(process.env.HOME, '.local/share/gem/ruby/*/gems/package-installer-cli-*'),
85
- // System gem installation paths
86
- '/usr/local/lib/ruby/gems/*/gems/package-installer-cli-*', '/var/lib/gems/*/gems/package-installer-cli-*');
87
- }
88
- // Rust cargo global paths
89
- if (process.env.HOME) {
90
- globalPaths.push(path.join(process.env.HOME, '.cargo/bin/package-installer-cli'), path.join(process.env.HOME, '.cargo/registry/src/*/package-installer-cli-*'));
91
- }
92
- // Go global paths
93
- const goPath = process.env.GOPATH || path.join(process.env.HOME || '', 'go');
94
- globalPaths.push(path.join(goPath, 'bin/go_package_installer_cli'), path.join(goPath, 'bin/pi'), // In case the binary is named 'pi'
95
- path.join(goPath, 'pkg/mod/github.com/0xshariq/go_package_installer_cli*'),
96
- // Also check system-wide go installation paths
97
- '/usr/local/bin/go_package_installer_cli', '/usr/local/bin/pi');
98
- // Check all possible global paths
90
+ // Check all global paths
99
91
  for (const globalPath of globalPaths) {
100
- // Handle wildcard paths
101
- if (globalPath.includes('*')) {
102
- try {
103
- const { execSync } = require('child_process');
104
- const expandedPaths = execSync(`ls -d ${globalPath} 2>/dev/null || true`, { encoding: 'utf8' }).trim().split('\n').filter((p) => p);
105
- for (const expandedPath of expandedPaths) {
106
- if (fs.existsSync(expandedPath) && (fs.existsSync(path.join(expandedPath, 'features')) ||
107
- fs.existsSync(path.join(path.dirname(expandedPath), 'features')))) {
108
- return fs.existsSync(path.join(expandedPath, 'features')) ? expandedPath : path.dirname(expandedPath);
109
- }
110
- }
111
- }
112
- catch (error) {
113
- // Continue to next path
114
- }
115
- }
116
- else {
117
- if (fs.existsSync(globalPath) && fs.existsSync(path.join(globalPath, 'features'))) {
118
- return globalPath;
119
- }
92
+ if (fs.existsSync(globalPath) && fs.existsSync(path.join(globalPath, 'features'))) {
93
+ return globalPath;
120
94
  }
121
95
  }
122
- // Method 5: Check if npm prefix is available and use it (for npm installations)
96
+ // Method 6: Check if npm prefix is available and use it (for npm installations)
123
97
  try {
124
98
  const { execSync } = require('child_process');
125
99
  const npmPrefix = execSync('npm config get prefix', { encoding: 'utf8' }).trim();
@@ -131,26 +105,14 @@ export function getCliRootPath() {
131
105
  catch (error) {
132
106
  // npm not available or command failed
133
107
  }
134
- // Method 6: Check binary location and work backwards (for compiled languages like Go/Rust)
135
- try {
136
- const { execSync } = require('child_process');
137
- const whichResult = execSync('which pi || which package-installer-cli || which go_package_installer_cli || echo ""', { encoding: 'utf8' }).trim();
138
- if (whichResult) {
139
- // Go up from binary location to find the package root
140
- let binaryDir = path.dirname(whichResult);
141
- while (binaryDir !== path.dirname(binaryDir)) {
142
- if (fs.existsSync(path.join(binaryDir, 'features'))) {
143
- return binaryDir;
144
- }
145
- binaryDir = path.dirname(binaryDir);
146
- }
147
- }
148
- }
149
- catch (error) {
150
- // which command failed or not available
108
+ // Method 7: Check relative to script location as last resort
109
+ const scriptRelativePath = path.resolve(__dirname, '../../');
110
+ if (fs.existsSync(path.join(scriptRelativePath, 'features'))) {
111
+ return scriptRelativePath;
151
112
  }
152
- // Final fallback: use the local development path
153
- console.warn('āš ļø Could not resolve CLI root path, using fallback');
113
+ // Final fallback: use the local development path but warn user
114
+ console.warn('āš ļø Could not resolve CLI root path, using fallback. Some features may not work correctly.');
115
+ console.warn('šŸ’” Try running with npx for better compatibility: npx @0xshariq/package-installer');
154
116
  return path.resolve(__dirname, '..', '..');
155
117
  }
156
118
  /**
data/dist/utils/utils.js CHANGED
@@ -18,14 +18,29 @@ const __dirname = path.dirname(__filename);
18
18
  */
19
19
  export function getPackageVersion() {
20
20
  try {
21
- const packageJsonPath = getPackageJsonPath();
22
- const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf-8');
23
- const packageJson = JSON.parse(packageJsonContent);
24
- return packageJson.version || '3.4.0';
21
+ // Try multiple paths to find package.json
22
+ const possiblePaths = [
23
+ getPackageJsonPath(),
24
+ path.resolve(process.cwd(), 'package.json'),
25
+ path.resolve(__dirname, '../../package.json'),
26
+ path.resolve(__dirname, '../../../package.json')
27
+ ];
28
+ for (const packagePath of possiblePaths) {
29
+ if (fs.existsSync(packagePath)) {
30
+ const packageJsonContent = fs.readFileSync(packagePath, 'utf-8');
31
+ const packageJson = JSON.parse(packageJsonContent);
32
+ if (packageJson.version) {
33
+ return packageJson.version;
34
+ }
35
+ }
36
+ }
37
+ // Fallback to hardcoded version as last resort
38
+ console.warn('Warning: Could not read version from package.json, using fallback version');
39
+ return '3.6.0';
25
40
  }
26
41
  catch (error) {
27
42
  console.warn('Warning: Could not read version from package.json, using fallback version');
28
- return '3.2.0';
43
+ return '3.6.0';
29
44
  }
30
45
  }
31
46
  /**
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.2.0
4
+ version: 1.3.0
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-28 00:00:00.000000000 Z
11
+ date: 2025-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -103,6 +103,7 @@ files:
103
103
  - dist/utils/dashboard.js
104
104
  - dist/utils/dependencyInstaller.js
105
105
  - dist/utils/featureInstaller.js
106
+ - dist/utils/helpFormatter.js
106
107
  - dist/utils/historyManager.js
107
108
  - dist/utils/languageConfig.js
108
109
  - dist/utils/pathResolver.js