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.
@@ -5,37 +5,56 @@ import chalk from 'chalk';
5
5
  import ora from 'ora';
6
6
  import fs from 'fs-extra';
7
7
  import path from 'path';
8
- import { displaySuccessMessage } from '../utils/dashboard.js';
8
+ import { createStandardHelp } from '../utils/helpFormatter.js';
9
+ import { displayCommandBanner } from '../utils/banner.js';
9
10
  /**
10
11
  * Display help for clean command
11
12
  */
12
13
  export function showCleanHelp() {
13
- console.clear();
14
- console.log(chalk.hex('#9c88ff')('🧹 CLEAN COMMAND HELP\n'));
15
- console.log(chalk.hex('#00d2d3')('Usage:'));
16
- console.log(chalk.white(' pi clean [options]'));
17
- console.log(chalk.white(' pi cleanup [options]') + chalk.gray(' (alias)\n'));
18
- console.log(chalk.hex('#00d2d3')('Description:'));
19
- console.log(chalk.white(' Clean development artifacts, caches, and temporary files'));
20
- console.log(chalk.white(' Safely removes common build outputs and dependency caches\n'));
21
- console.log(chalk.hex('#00d2d3')('Options:'));
22
- console.log(chalk.white(' --node-modules') + chalk.gray(' Clean node_modules directories'));
23
- console.log(chalk.white(' --build') + chalk.gray(' Clean build/dist directories'));
24
- console.log(chalk.white(' --cache') + chalk.gray(' Clean package manager caches'));
25
- console.log(chalk.white(' --logs') + chalk.gray(' Clean log files'));
26
- console.log(chalk.white(' --all') + chalk.gray(' Clean everything (safe)'));
27
- console.log(chalk.white(' --deep') + chalk.gray(' Deep clean (includes lock files)'));
28
- console.log(chalk.white(' --dry-run') + chalk.gray(' Preview what would be cleaned'));
29
- console.log(chalk.white(' -h, --help') + chalk.gray(' Show this help message\n'));
30
- console.log(chalk.hex('#00d2d3')('Examples:'));
31
- console.log(chalk.gray(' # Clean build directories'));
32
- console.log(chalk.white(' pi clean --build\n'));
33
- console.log(chalk.gray(' # Clean node_modules'));
34
- console.log(chalk.white(' pi clean --node-modules\n'));
35
- console.log(chalk.gray(' # Preview clean operation'));
36
- console.log(chalk.white(' pi clean --all --dry-run\n'));
37
- console.log(chalk.gray(' # Deep clean with lock files'));
38
- console.log(chalk.white(' pi clean --deep\n'));
14
+ const helpConfig = {
15
+ commandName: 'Clean',
16
+ emoji: '🧹',
17
+ description: 'Clean development artifacts, caches, and temporary files.\nSafely removes common build outputs, dependency caches, and temporary files to free up disk space and clean your project.',
18
+ usage: [
19
+ 'clean [options]',
20
+ 'cleanup [options] # alias'
21
+ ],
22
+ options: [
23
+ { flag: '--node-modules', description: 'Clean node_modules directories' },
24
+ { flag: '--build', description: 'Clean build/dist directories' },
25
+ { flag: '--cache', description: 'Clean package manager caches' },
26
+ { flag: '--logs', description: 'Clean log files and debug outputs' },
27
+ { flag: '--all', description: 'Clean everything (safe operation)' },
28
+ { flag: '--deep', description: 'Deep clean (includes lock files)' },
29
+ { flag: '--dry-run', description: 'Preview what would be cleaned' }
30
+ ],
31
+ examples: [
32
+ { command: 'clean --build', description: 'Clean build directories only' },
33
+ { command: 'clean --node-modules', description: 'Clean node_modules directories' },
34
+ { command: 'clean --all --dry-run', description: 'Preview what would be cleaned' },
35
+ { command: 'clean --deep', description: 'Deep clean with lock files' },
36
+ { command: 'clean --cache', description: 'Clean package manager caches' },
37
+ { command: 'cleanup --all', description: 'Use alias command' }
38
+ ],
39
+ additionalSections: [
40
+ {
41
+ title: 'Clean Targets',
42
+ items: [
43
+ 'Build Outputs: dist, build, .next, out, target',
44
+ 'Dependencies: node_modules, .pnpm-store',
45
+ 'Caches: .cache, .npm, .yarn, __pycache__',
46
+ 'Logs: *.log, npm-debug.log, yarn-error.log',
47
+ 'Temp Files: .DS_Store, Thumbs.db, *.tmp'
48
+ ]
49
+ }
50
+ ],
51
+ tips: [
52
+ 'Always use --dry-run first to preview changes',
53
+ 'Deep clean removes lock files and requires dependency reinstall',
54
+ 'Use --cache to clean package manager caches for more space'
55
+ ]
56
+ };
57
+ createStandardHelp(helpConfig);
39
58
  }
40
59
  /**
41
60
  * Main clean command function
@@ -46,63 +65,63 @@ export async function cleanCommand(options = {}) {
46
65
  showCleanHelp();
47
66
  return;
48
67
  }
49
- // Blue gradient banner with "CLEANER" on next line
50
- console.clear();
51
- const banner = `\n${chalk.bgHex('#00c6ff').hex('#fff').bold(' PROJECT ')}${chalk.bgHex('#0072ff').hex('#fff').bold(' CLEAN ')}\n${chalk.bgHex('#00c6ff').hex('#fff').bold(' ER ')}\n`;
52
- console.log(banner);
68
+ // Display command banner
69
+ displayCommandBanner('Clean', 'Clean development artifacts, caches, and temporary files from your project');
70
+ console.log(chalk.hex('#ffa502')('🧹 Project Cleaner\n'));
53
71
  const projectPath = process.cwd();
54
- // Improved flag logic
55
- const cleanTargets = [];
56
- if (options['all']) {
57
- cleanTargets.push('node-modules', 'build', 'cache', 'logs');
58
- if (options['deep'])
59
- cleanTargets.push('lock-files');
60
- }
61
- else {
62
- if (options['node-modules'])
63
- cleanTargets.push('node-modules');
64
- if (options['build'])
65
- cleanTargets.push('build');
66
- if (options['cache'])
67
- cleanTargets.push('cache');
68
- if (options['logs'])
69
- cleanTargets.push('logs');
70
- if (options['deep'])
71
- cleanTargets.push('lock-files');
72
- }
73
- if (cleanTargets.length === 0) {
74
- console.log(chalk.yellow('No clean targets specified. Use --help for options.'));
72
+ const isDryRun = options['dryRun'] || options['dry-run'];
73
+ // Determine what to clean based on flags
74
+ const targets = determineCleanTargets(options);
75
+ if (targets.length === 0) {
76
+ console.log(chalk.yellow('⚠️ No clean targets specified. Use --help for available options.'));
77
+ console.log(chalk.gray('💡 Tip: Use --all for a safe clean of common artifacts'));
75
78
  return;
76
79
  }
77
- if (options['dry-run']) {
78
- console.log(chalk.yellow('🔍 DRY RUN - Showing what would be cleaned:\n'));
80
+ if (isDryRun) {
81
+ console.log(chalk.cyan('🔍 DRY RUN - Preview of what would be cleaned:\n'));
79
82
  }
80
- const spinner = ora(chalk.hex('#9c88ff')('🧹 Cleaning project...')).start();
83
+ else {
84
+ console.log(chalk.cyan('🧹 Starting cleanup process...\n'));
85
+ }
86
+ const spinner = ora(chalk.hex('#ffa502')(isDryRun ? 'Analyzing files...' : 'Cleaning project...')).start();
81
87
  try {
82
- let totalCleaned = 0;
88
+ let totalSize = 0;
83
89
  const results = [];
84
- for (const target of cleanTargets) {
85
- // ...existing code for cleaning each target...
86
- // Simulate cleaning for dry-run
87
- const size = 1024 * Math.floor(Math.random() * 10 + 1); // Dummy size
88
- if (size > 0) {
89
- totalCleaned += size;
90
- results.push(`${target}: ${size} bytes`);
90
+ let itemsCleaned = 0;
91
+ for (const target of targets) {
92
+ spinner.text = `${isDryRun ? 'Analyzing' : 'Cleaning'} ${target.name}...`;
93
+ const targetSize = await cleanTarget(projectPath, target, isDryRun);
94
+ if (targetSize > 0) {
95
+ totalSize += targetSize;
96
+ itemsCleaned++;
97
+ results.push(`${target.name}: ${formatFileSize(targetSize)}`);
91
98
  }
92
99
  }
93
100
  spinner.stop();
94
- if (totalCleaned > 0) {
95
- displaySuccessMessage(options['dry-run'] ? 'Clean preview completed!' : 'Project cleaned successfully!', [
96
- `Total ${options['dry-run'] ? 'would be' : ''} cleaned: ${totalCleaned} bytes`,
97
- ...results
98
- ]);
101
+ if (totalSize > 0) {
102
+ const action = isDryRun ? 'would be cleaned' : 'cleaned';
103
+ console.log(chalk.green(`\n✅ ${isDryRun ? 'Analysis' : 'Cleanup'} completed!`));
104
+ console.log(chalk.white(`📊 Total ${action}: ${chalk.bold(formatFileSize(totalSize))}`));
105
+ console.log(chalk.white(`📁 Items ${action}: ${chalk.bold(itemsCleaned)}`));
106
+ if (results.length > 0) {
107
+ console.log(chalk.cyan('\n📋 Breakdown:'));
108
+ results.forEach(result => {
109
+ console.log(chalk.gray(` • ${result}`));
110
+ });
111
+ }
112
+ if (isDryRun) {
113
+ console.log(chalk.yellow('\n💡 Run without --dry-run to actually clean these files'));
114
+ }
115
+ else {
116
+ console.log(chalk.green('\n🎉 Project successfully cleaned!'));
117
+ }
99
118
  }
100
119
  else {
101
- console.log(chalk.yellow('✨ Nothing to clean - project is already tidy!'));
120
+ console.log(chalk.green('✨ Nothing to clean - project is already tidy!'));
102
121
  }
103
122
  }
104
123
  catch (error) {
105
- spinner.fail(chalk.red('❌ Failed to clean project'));
124
+ spinner.fail(chalk.red(isDryRun ? '❌ Failed to analyze files' : '❌ Failed to clean project'));
106
125
  console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
107
126
  process.exit(1);
108
127
  }
@@ -112,49 +131,59 @@ export async function cleanCommand(options = {}) {
112
131
  */
113
132
  function determineCleanTargets(options) {
114
133
  const targets = [];
115
- if (options.all || options.nodeModules) {
134
+ // Handle --node-modules flag
135
+ if (options.all || options['nodeModules'] || options['node-modules']) {
116
136
  targets.push({
117
137
  name: 'node_modules',
118
- patterns: ['**/node_modules'],
138
+ patterns: ['node_modules', '**/node_modules'],
119
139
  description: 'Node.js dependencies'
120
140
  });
121
141
  }
142
+ // Handle --build flag
122
143
  if (options.all || options.build) {
123
144
  targets.push({
124
145
  name: 'build outputs',
125
- patterns: ['dist', 'build', '.next', 'out', 'target/debug', 'target/release'],
146
+ patterns: ['dist', 'build', '.next', 'out', 'target/debug', 'target/release', '.output', '.nuxt'],
126
147
  description: 'Build outputs and compiled files'
127
148
  });
128
149
  }
150
+ // Handle --cache flag
129
151
  if (options.all || options.cache) {
130
152
  targets.push({
131
- name: 'caches',
132
- patterns: ['.cache', '.npm', '.yarn', '.pnpm-store', '__pycache__'],
153
+ name: 'package manager caches',
154
+ patterns: ['.cache', '.npm', '.yarn', '.pnpm-store', '.pnpm', '__pycache__', '.pytest_cache', 'target/debug/deps', 'target/release/deps'],
133
155
  description: 'Package manager and build caches'
134
156
  });
135
157
  }
158
+ // Handle --logs flag
136
159
  if (options.all || options.logs) {
137
160
  targets.push({
138
- name: 'logs',
139
- patterns: ['*.log', 'logs/**', '.log'],
140
- description: 'Log files'
161
+ name: 'log files',
162
+ patterns: ['*.log', 'logs', 'log', '*.log.*', 'npm-debug.log*', 'yarn-debug.log*', 'yarn-error.log*'],
163
+ description: 'Log files and debug outputs'
141
164
  });
142
165
  }
166
+ // Handle --deep flag (includes lock files)
143
167
  if (options.deep) {
144
168
  targets.push({
145
- name: 'lock files',
146
- patterns: ['package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'Cargo.lock'],
169
+ name: 'dependency lock files',
170
+ patterns: ['package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'Cargo.lock', 'Pipfile.lock', 'poetry.lock'],
147
171
  description: 'Dependency lock files (requires reinstall)'
148
172
  });
149
- }
150
- // Default to safe clean if no options specified
151
- if (targets.length === 0) {
173
+ // Add more aggressive cleaning for deep clean
152
174
  targets.push({
153
- name: 'build outputs',
154
- patterns: ['dist', 'build', '.next', 'out'],
155
- description: 'Build outputs (safe to clean)'
175
+ name: 'temporary files',
176
+ patterns: ['.tmp', 'tmp', '.temp', 'temp', '.DS_Store', 'Thumbs.db', '*.tmp', '*.temp'],
177
+ description: 'Temporary files and system artifacts'
156
178
  });
157
179
  }
180
+ // If no specific options are provided and not --all, show available options
181
+ const hasSpecificOption = options['nodeModules'] || options['node-modules'] ||
182
+ options.build || options.cache || options.logs ||
183
+ options.deep || options.all;
184
+ if (!hasSpecificOption) {
185
+ return []; // Return empty to show help message
186
+ }
158
187
  return targets;
159
188
  }
160
189
  /**
@@ -163,22 +192,132 @@ function determineCleanTargets(options) {
163
192
  async function cleanTarget(projectPath, target, dryRun) {
164
193
  let totalSize = 0;
165
194
  for (const pattern of target.patterns) {
166
- const fullPath = path.join(projectPath, pattern);
167
195
  try {
168
- if (await fs.pathExists(fullPath)) {
169
- const stat = await fs.stat(fullPath);
170
- totalSize += await getDirectorySize(fullPath);
171
- if (!dryRun) {
172
- await fs.remove(fullPath);
196
+ // Handle different pattern types
197
+ if (pattern.includes('*')) {
198
+ // Handle glob patterns
199
+ totalSize += await cleanGlobPattern(projectPath, pattern, dryRun);
200
+ }
201
+ else {
202
+ // Handle direct paths
203
+ const fullPath = path.join(projectPath, pattern);
204
+ if (await fs.pathExists(fullPath)) {
205
+ const size = await getDirectorySize(fullPath);
206
+ totalSize += size;
207
+ if (!dryRun && size > 0) {
208
+ await fs.remove(fullPath);
209
+ }
173
210
  }
174
211
  }
175
212
  }
176
213
  catch (error) {
177
- // Ignore permission errors or non-existent paths
214
+ // Silently ignore permission errors or other filesystem issues
215
+ // This is expected behavior for clean operations
178
216
  }
179
217
  }
180
218
  return totalSize;
181
219
  }
220
+ /**
221
+ * Clean files matching a glob pattern
222
+ */
223
+ async function cleanGlobPattern(projectPath, pattern, dryRun) {
224
+ let totalSize = 0;
225
+ try {
226
+ // Import glob dynamically
227
+ const { glob } = await import('glob');
228
+ const matches = await glob(pattern, {
229
+ cwd: projectPath,
230
+ absolute: false,
231
+ dot: true,
232
+ ignore: ['node_modules/node_modules/**'] // Avoid nested node_modules issues
233
+ });
234
+ const matchArray = Array.isArray(matches) ? matches : [matches];
235
+ for (const match of matchArray) {
236
+ if (!match)
237
+ continue;
238
+ const fullPath = path.join(projectPath, match);
239
+ try {
240
+ if (await fs.pathExists(fullPath)) {
241
+ const size = await getDirectorySize(fullPath);
242
+ totalSize += size;
243
+ if (!dryRun && size > 0) {
244
+ await fs.remove(fullPath);
245
+ }
246
+ }
247
+ }
248
+ catch (error) {
249
+ // Skip files that can't be accessed
250
+ }
251
+ }
252
+ }
253
+ catch (error) {
254
+ // Fallback to simple directory walking for pattern matching
255
+ totalSize += await fallbackPatternMatch(projectPath, pattern, dryRun);
256
+ }
257
+ return totalSize;
258
+ }
259
+ /**
260
+ * Fallback pattern matching when glob is not available
261
+ */
262
+ async function fallbackPatternMatch(projectPath, pattern, dryRun) {
263
+ let totalSize = 0;
264
+ // Handle common patterns manually
265
+ if (pattern.includes('**')) {
266
+ // Recursive pattern - search directories
267
+ const basePattern = pattern.replace('**/', '').replace('*', '');
268
+ await walkDirectory(projectPath, async (filePath) => {
269
+ if (filePath.includes(basePattern)) {
270
+ try {
271
+ const size = await getDirectorySize(filePath);
272
+ totalSize += size;
273
+ if (!dryRun && size > 0) {
274
+ await fs.remove(filePath);
275
+ }
276
+ }
277
+ catch (error) {
278
+ // Skip on error
279
+ }
280
+ }
281
+ });
282
+ }
283
+ else {
284
+ // Simple pattern
285
+ const simplePattern = pattern.replace('*', '');
286
+ const fullPath = path.join(projectPath, simplePattern);
287
+ if (await fs.pathExists(fullPath)) {
288
+ const size = await getDirectorySize(fullPath);
289
+ totalSize += size;
290
+ if (!dryRun && size > 0) {
291
+ await fs.remove(fullPath);
292
+ }
293
+ }
294
+ }
295
+ return totalSize;
296
+ }
297
+ /**
298
+ * Walk directory recursively
299
+ */
300
+ async function walkDirectory(dir, callback) {
301
+ try {
302
+ const entries = await fs.readdir(dir, { withFileTypes: true });
303
+ for (const entry of entries) {
304
+ const fullPath = path.join(dir, entry.name);
305
+ if (entry.isDirectory()) {
306
+ await callback(fullPath);
307
+ // Recurse into subdirectory (with depth limit to avoid infinite loops)
308
+ if (!entry.name.startsWith('.') && entry.name !== 'node_modules') {
309
+ await walkDirectory(fullPath, callback);
310
+ }
311
+ }
312
+ else {
313
+ await callback(fullPath);
314
+ }
315
+ }
316
+ }
317
+ catch (error) {
318
+ // Skip directories that can't be read
319
+ }
320
+ }
182
321
  /**
183
322
  * Get directory size recursively
184
323
  */
@@ -1,54 +1,73 @@
1
1
  import chalk from 'chalk';
2
- import gradient from 'gradient-string';
3
- import boxen from 'boxen';
4
2
  import path from 'path';
5
3
  import { cloneRepo as cloneRepoUtil } from '../utils/cloneUtils.js';
6
4
  import { CacheManager } from '../utils/cacheUtils.js';
5
+ import { createStandardHelp } from '../utils/helpFormatter.js';
7
6
  /**
8
- * Display help for clone command
7
+ * Display help for clone command using standardized format
9
8
  */
10
9
  export function showCloneHelp() {
11
- const piGradient = gradient(['#00c6ff', '#0072ff']);
12
- const headerGradient = gradient(['#4facfe', '#00f2fe']);
13
- console.log('\n' + boxen(headerGradient('📥 Clone Command Help') + '\n\n' +
14
- chalk.white('Clone any public repository from GitHub, GitLab, BitBucket, or SourceHut.') + '\n' +
15
- chalk.white('Automatically installs dependencies, creates .env files, and tracks usage.') + '\n\n' +
16
- chalk.cyan('Usage:') + '\n' +
17
- chalk.white(` ${piGradient('pi')} ${chalk.hex('#00d2d3')('clone')} <user/repo> [project-name]`) + '\n\n' +
18
- chalk.cyan('Options:') + '\n' +
19
- chalk.gray(' -h, --help Display help for this command') + '\n' +
20
- chalk.gray(' --offline Use cached templates if available') + '\n' +
21
- chalk.gray(' --no-deps Skip dependency installation') + '\n' +
22
- chalk.gray(' --no-git Skip git initialization') + '\n\n' +
23
- chalk.cyan('Examples:') + '\n' +
24
- chalk.gray(` ${piGradient('pi')} ${chalk.hex('#00d2d3')('clone')} facebook/react my-react-copy # Clone from GitHub with custom name`) + '\n' +
25
- chalk.gray(` ${piGradient('pi')} ${chalk.hex('#00d2d3')('clone')} gitlab:user/project # Clone from GitLab`) + '\n' +
26
- chalk.gray(` ${piGradient('pi')} ${chalk.hex('#00d2d3')('clone')} bitbucket:user/repo # Clone from BitBucket`) + '\n' +
27
- chalk.gray(` ${piGradient('pi')} ${chalk.hex('#00d2d3')('clone')} sourcehut:user/repo # Clone from SourceHut`) + '\n' +
28
- chalk.gray(` ${piGradient('pi')} ${chalk.hex('#00d2d3')('clone')} user/repo ${chalk.hex('#ff6b6b')('--offline')} # Use cached version if available`) + '\n' +
29
- chalk.gray(` ${piGradient('pi')} ${chalk.hex('#00d2d3')('clone')} ${chalk.hex('#ff6b6b')('--help')} # Show this help message`) + '\n\n' +
30
- chalk.hex('#00d2d3')('💡 Supported Platforms:') + '\n' +
31
- chalk.hex('#95afc0')(' • GitHub (default): user/repo') + '\n' +
32
- chalk.hex('#95afc0')(' • GitLab: gitlab:user/repo') + '\n' +
33
- chalk.hex('#95afc0')(' • BitBucket: bitbucket:user/repo') + '\n' +
34
- chalk.hex('#95afc0')(' • SourceHut: sourcehut:user/repo') + '\n\n' +
35
- chalk.hex('#ffa502')('⚡ Features:') + '\n' +
36
- chalk.hex('#95afc0')(' • Automatic dependency installation') + '\n' +
37
- chalk.hex('#95afc0')(' • Environment file creation from templates') + '\n' +
38
- chalk.hex('#95afc0')(' • Git repository initialization') + '\n' +
39
- chalk.hex('#95afc0')(' • Usage tracking and history') + '\n' +
40
- chalk.hex('#95afc0')(' • Offline mode with cached templates'), {
41
- padding: 1,
42
- borderStyle: 'round',
43
- borderColor: 'cyan',
44
- backgroundColor: '#0a0a0a'
45
- }));
10
+ const helpConfig = {
11
+ commandName: 'Clone',
12
+ emoji: '📥',
13
+ description: 'Clone any public repository from GitHub, GitLab, BitBucket, or SourceHut.\nAutomatically installs dependencies, creates .env files, and tracks usage.',
14
+ usage: [
15
+ 'clone <user/repo> [project-name] [options]',
16
+ 'clone [options]'
17
+ ],
18
+ options: [
19
+ { flag: '--offline', description: 'Use cached templates if available' },
20
+ { flag: '--no-deps', description: 'Skip dependency installation' },
21
+ { flag: '--no-git', description: 'Skip git initialization' },
22
+ { flag: '--shallow', description: 'Create shallow clone (faster)' },
23
+ { flag: '--branch <name>', description: 'Clone specific branch' },
24
+ { flag: '--template', description: 'Treat as template repository' }
25
+ ],
26
+ examples: [
27
+ { command: 'clone facebook/react', description: 'Clone from GitHub' },
28
+ { command: 'clone facebook/react my-app', description: 'Clone with custom name' },
29
+ { command: 'clone gitlab:user/project', description: 'Clone from GitLab' },
30
+ { command: 'clone bitbucket:user/repo', description: 'Clone from BitBucket' },
31
+ { command: 'clone sourcehut:user/repo', description: 'Clone from SourceHut' },
32
+ { command: 'clone user/repo --offline', description: 'Use cached version' },
33
+ { command: 'clone user/repo --no-deps', description: 'Skip dependencies' },
34
+ { command: 'clone user/repo --shallow', description: 'Shallow clone' }
35
+ ],
36
+ additionalSections: [
37
+ {
38
+ title: 'Supported Platforms',
39
+ items: [
40
+ 'GitHub (default): user/repo',
41
+ 'GitLab: gitlab:user/repo',
42
+ 'BitBucket: bitbucket:user/repo',
43
+ 'SourceHut: sourcehut:user/repo'
44
+ ]
45
+ },
46
+ {
47
+ title: 'Features',
48
+ items: [
49
+ 'Automatic dependency installation',
50
+ 'Environment file creation from templates',
51
+ 'Git repository initialization',
52
+ 'Usage tracking and history',
53
+ 'Offline mode with cached templates',
54
+ 'Shallow cloning for faster downloads',
55
+ 'Branch-specific cloning'
56
+ ]
57
+ }
58
+ ],
59
+ tips: [
60
+ 'Use --offline flag for cached repositories to work without internet',
61
+ 'Shallow clones are faster but have limited git history'
62
+ ]
63
+ };
64
+ createStandardHelp(helpConfig);
46
65
  }
47
66
  export async function cloneRepo(userRepo, projectName, options = {}) {
48
67
  const startTime = Date.now();
49
68
  const cacheManager = new CacheManager();
50
69
  // Check for help flag
51
- if (userRepo === '--help' || userRepo === '-h') {
70
+ if (options.help || options['-h'] || options['--help']) {
52
71
  showCloneHelp();
53
72
  return;
54
73
  }
@@ -58,12 +77,14 @@ export async function cloneRepo(userRepo, projectName, options = {}) {
58
77
  actualProjectName = path.basename(process.cwd());
59
78
  console.log(chalk.cyan(`Using current directory name: ${chalk.bold(actualProjectName)}`));
60
79
  }
61
- // Parse additional options from arguments
62
- const args = process.argv.slice(3);
80
+ // Configure clone options from passed options
63
81
  const cloneOptions = {
64
- offline: args.includes('--offline'),
65
- noDeps: args.includes('--no-deps'),
66
- noGit: args.includes('--no-git'),
82
+ offline: options.offline || false,
83
+ noDeps: options.noDeps || options['no-deps'] || false,
84
+ noGit: options.noGit || options['no-git'] || false,
85
+ shallow: options.shallow || false,
86
+ branch: options.branch || null,
87
+ template: options.template || false,
67
88
  ...options
68
89
  };
69
90
  try {