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