vibecodingmachine-cli 2026.2.20-438 → 2026.2.26-1739
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.
- package/bin/auth/auth-compliance.js +126 -0
- package/bin/cli-program.js +104 -0
- package/bin/cli-setup.js +52 -0
- package/bin/commands/agent-commands.js +310 -0
- package/bin/commands/auto-commands.js +70 -0
- package/bin/commands/command-aliases.js +118 -0
- package/bin/commands/repo-commands.js +39 -0
- package/bin/commands/rui-commands.js +152 -0
- package/bin/config/cli-config.js +394 -0
- package/bin/init/environment-setup.js +84 -0
- package/bin/update/update-checker.js +126 -0
- package/bin/vibecodingmachine-new.js +50 -0
- package/bin/vibecodingmachine.js +29 -663
- package/package.json +8 -2
- package/src/commands/agents/add.js +277 -0
- package/src/commands/agents/check.js +380 -0
- package/src/commands/agents/list.js +471 -0
- package/src/commands/agents/remove.js +351 -0
- package/src/commands/analyze-file-sizes.js +428 -0
- package/src/commands/auto-direct/code-processor.js +282 -0
- package/src/commands/auto-direct/file-scanner.js +266 -0
- package/src/commands/auto-direct/provider-config.js +178 -0
- package/src/commands/auto-direct/provider-manager.js +219 -0
- package/src/commands/auto-direct/requirement-manager.js +172 -0
- package/src/commands/auto-direct/status-display.js +91 -0
- package/src/commands/auto-direct/utils.js +106 -0
- package/src/commands/auto-direct.js +875 -488
- package/src/commands/auto-execution.js +342 -0
- package/src/commands/auto-provider-management.js +102 -0
- package/src/commands/auto-requirement-management.js +161 -0
- package/src/commands/auto-status-helpers.js +141 -0
- package/src/commands/auto.js +105 -5155
- package/src/commands/check-compliance.js +536 -0
- package/src/commands/continuous-scan.js +119 -0
- package/src/commands/ide.js +16 -4
- package/src/commands/refactor-file.js +486 -0
- package/src/commands/requirements.js +301 -2
- package/src/commands/timeout.js +290 -0
- package/src/trui/TruiInterface.js +108 -0
- package/src/trui/agents/AgentInterface.js +580 -0
- package/src/utils/antigravity-installer.js +60 -6
- package/src/utils/clarification-actions.js +290 -0
- package/src/utils/config.js +123 -2
- package/src/utils/first-run.js +5 -5
- package/src/utils/ide-handlers.js +212 -0
- package/src/utils/interactive/clarification-actions.js +348 -0
- package/src/utils/interactive/core-ui.js +265 -0
- package/src/utils/interactive/file-backup.js +237 -0
- package/src/utils/interactive/file-import-export.js +305 -0
- package/src/utils/interactive/file-operations.js +49 -0
- package/src/utils/interactive/file-validation.js +276 -0
- package/src/utils/interactive/interactive-prompts.js +480 -0
- package/src/utils/interactive/requirement-actions.js +127 -0
- package/src/utils/interactive/requirement-crud.js +356 -0
- package/src/utils/interactive/requirements-navigation.js +286 -0
- package/src/utils/interactive.js +390 -3459
- package/src/utils/provider-checker/agent-checker.js +250 -0
- package/src/utils/provider-checker/agent-runner.js +450 -0
- package/src/utils/provider-checker/cli-installer.js +123 -0
- package/src/utils/provider-checker/cli-utils.js +15 -0
- package/src/utils/provider-checker/format-utils.js +32 -0
- package/src/utils/provider-checker/ide-manager.js +72 -0
- package/src/utils/provider-checker/ide-utils.js +71 -0
- package/src/utils/provider-checker/node-detector.js +56 -0
- package/src/utils/provider-checker/node-utils.js +61 -0
- package/src/utils/provider-checker/process-spawn.js +22 -0
- package/src/utils/provider-checker/process-utils.js +37 -0
- package/src/utils/provider-checker/provider-validator.js +160 -0
- package/src/utils/provider-checker/quota-checker.js +54 -0
- package/src/utils/provider-checker/quota-detector.js +44 -0
- package/src/utils/provider-checker/requirements-manager.js +94 -0
- package/src/utils/provider-checker/test-requirements.js +95 -0
- package/src/utils/provider-checker/time-formatter.js +18 -0
- package/src/utils/provider-checker-new.js +14 -0
- package/src/utils/provider-checker.js +12 -407
- package/src/utils/provider-checkers/ide-manager.js +128 -0
- package/src/utils/provider-checkers/node-executable-finder.js +51 -0
- package/src/utils/provider-checkers/provider-checker-core.js +172 -0
- package/src/utils/provider-checkers/provider-checker-main.js +107 -0
- package/src/utils/provider-manager.js +60 -4
- package/src/utils/provider-registry.js +26 -3
- package/src/utils/provider-utils.js +173 -0
- package/src/utils/quota-detectors.js +212 -0
- package/src/utils/requirement-action-handlers.js +288 -0
- package/src/utils/requirement-actions/clarification-actions.js +229 -0
- package/src/utils/requirement-actions/confirmation-prompts.js +93 -0
- package/src/utils/requirement-actions/file-operations.js +92 -0
- package/src/utils/requirement-actions/helpers.js +40 -0
- package/src/utils/requirement-actions/requirement-operations.js +335 -0
- package/src/utils/requirement-actions.js +46 -856
- package/src/utils/requirement-file-operations.js +259 -0
- package/src/utils/requirement-helpers.js +128 -0
- package/src/utils/requirement-management.js +279 -0
- package/src/utils/requirement-navigation.js +146 -0
- package/src/utils/requirement-organization.js +271 -0
- package/src/utils/simple-trui.js +75 -1
- package/src/utils/trui-navigation.js +28 -2
- package/src/utils/trui-req-tree.js +196 -11
- package/src/utils/trui-specifications.js +31 -1
- package/src/utils/interactive-backup.js +0 -5664
- package/src/utils/trui-provider-manager.js +0 -182
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Command: Analyze File Sizes
|
|
3
|
+
*
|
|
4
|
+
* Command-line interface for analyzing file sizes across the codebase.
|
|
5
|
+
* Provides comprehensive analysis and refactoring recommendations.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { Command } = require('commander');
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
// Import analysis components
|
|
14
|
+
const { CodebaseScanner } = require('@vibecodingmachine/core/src/analysis/codebase-scanner');
|
|
15
|
+
const { LineCounter } = require('@vibecodingmachine/core/src/analysis/line-counter');
|
|
16
|
+
const { FileCategorizer } = require('@vibecodingmachine/core/src/analysis/categorizer');
|
|
17
|
+
const { BoundaryDetector } = require('@vibecodingmachine/core/src/analysis/boundary-detector');
|
|
18
|
+
const { StrategyGenerator } = require('@vibecodingmachine/core/src/analysis/strategy-generator');
|
|
19
|
+
const { PriorityCalculator } = require('@vibecodingmachine/core/src/analysis/priority-calculator');
|
|
20
|
+
const { AnalysisReporter } = require('@vibecodingmachine/core/src/analysis/analysis-reporter');
|
|
21
|
+
const { FileAnalysis } = require('@vibecodingmachine/core/src/models/file-analysis');
|
|
22
|
+
const { FileAnalysisCollection } = require('@vibecodingmachine/core/src/models/file-analysis');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Analyze file sizes command
|
|
26
|
+
*/
|
|
27
|
+
class AnalyzeFileSizesCommand {
|
|
28
|
+
constructor() {
|
|
29
|
+
this.command = new Command('analyze-file-sizes');
|
|
30
|
+
this.setupCommand();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
setupCommand() {
|
|
34
|
+
this.command
|
|
35
|
+
.description('Analyze file sizes across the codebase and generate refactoring recommendations')
|
|
36
|
+
.option('-p, --path <path>', 'Path to analyze (default: current directory)', process.cwd())
|
|
37
|
+
.option('-o, --output <path>', 'Output file for the report')
|
|
38
|
+
.option('-f, --format <format>', 'Report format (json, markdown, html)', 'json')
|
|
39
|
+
.option('--include-tests', 'Include test files in analysis', false)
|
|
40
|
+
.option('--include-vendor', 'Include vendor/third-party files', false)
|
|
41
|
+
.option('--max-depth <depth>', 'Maximum directory depth to scan', '10')
|
|
42
|
+
.option('--min-lines <lines>', 'Minimum lines to include in detailed analysis', '10')
|
|
43
|
+
.option('--limit <lines>', 'File size limit to check against', '555')
|
|
44
|
+
.option('--verbose', 'Verbose output', false)
|
|
45
|
+
.option('--quiet', 'Minimal output', false)
|
|
46
|
+
.action(async (options) => {
|
|
47
|
+
try {
|
|
48
|
+
await this.execute(options);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error(chalk.red('Error:'), error.message);
|
|
51
|
+
if (options.verbose) {
|
|
52
|
+
console.error(error.stack);
|
|
53
|
+
}
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async execute(options) {
|
|
60
|
+
const startTime = Date.now();
|
|
61
|
+
|
|
62
|
+
if (!options.quiet) {
|
|
63
|
+
console.log(chalk.blue('🔍 Starting file size analysis...'));
|
|
64
|
+
console.log(chalk.gray(`Path: ${options.path}`));
|
|
65
|
+
console.log(chalk.gray(`Format: ${options.format}`));
|
|
66
|
+
if (options.output) {
|
|
67
|
+
console.log(chalk.gray(`Output: ${options.output}`));
|
|
68
|
+
}
|
|
69
|
+
console.log();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Step 1: Scan codebase
|
|
73
|
+
const scanResults = await this.scanCodebase(options);
|
|
74
|
+
|
|
75
|
+
// Step 2: Count lines
|
|
76
|
+
const lineResults = await this.countLines(scanResults, options);
|
|
77
|
+
|
|
78
|
+
// Step 3: Categorize files
|
|
79
|
+
const categorizationResults = await this.categorizeFiles(lineResults, options);
|
|
80
|
+
|
|
81
|
+
// Step 4: Detect boundaries
|
|
82
|
+
const boundaryResults = await this.detectBoundaries(lineResults, options);
|
|
83
|
+
|
|
84
|
+
// Step 5: Calculate priorities
|
|
85
|
+
const priorityResults = await this.calculatePriorities(lineResults, boundaryResults, options);
|
|
86
|
+
|
|
87
|
+
// Step 6: Generate strategies
|
|
88
|
+
const strategyResults = await this.generateStrategies(lineResults, priorityResults, options);
|
|
89
|
+
|
|
90
|
+
// Step 7: Generate report
|
|
91
|
+
const reportResults = await this.generateReport(
|
|
92
|
+
lineResults,
|
|
93
|
+
categorizationResults,
|
|
94
|
+
priorityResults,
|
|
95
|
+
strategyResults,
|
|
96
|
+
options
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const duration = Date.now() - startTime;
|
|
100
|
+
|
|
101
|
+
if (!options.quiet) {
|
|
102
|
+
this.printSummary(reportResults, duration);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (options.output) {
|
|
106
|
+
await this.saveReport(reportResults, options);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return reportResults;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async scanCodebase(options) {
|
|
113
|
+
if (!options.quiet) {
|
|
114
|
+
console.log(chalk.yellow('📁 Scanning codebase...'));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const scanner = new CodebaseScanner();
|
|
118
|
+
const results = await scanner.scan(options.path);
|
|
119
|
+
|
|
120
|
+
if (options.verbose) {
|
|
121
|
+
console.log(chalk.gray(`Found ${results.length} files to analyze`));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return results;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async countLines(scanResults, options) {
|
|
128
|
+
if (!options.quiet) {
|
|
129
|
+
console.log(chalk.yellow('📏 Counting lines...'));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const lineCounter = new LineCounter();
|
|
133
|
+
const filePaths = scanResults.map(result => result.path);
|
|
134
|
+
const lineResults = lineCounter.countFiles(filePaths);
|
|
135
|
+
|
|
136
|
+
// Create file analysis objects
|
|
137
|
+
const fileAnalyses = [];
|
|
138
|
+
for (let i = 0; i < scanResults.length; i++) {
|
|
139
|
+
const scanResult = scanResults[i];
|
|
140
|
+
const lineResult = lineResults[i];
|
|
141
|
+
|
|
142
|
+
const analysis = new FileAnalysis(scanResult.path);
|
|
143
|
+
analysis.setLineCountMetrics(
|
|
144
|
+
lineResult.totalLines,
|
|
145
|
+
lineResult.codeLines,
|
|
146
|
+
lineResult.commentLines,
|
|
147
|
+
lineResult.blankLines
|
|
148
|
+
);
|
|
149
|
+
analysis.setFileTypeFlags(
|
|
150
|
+
lineResult.extension.includes('test') || scanResult.relativePath.includes('test'),
|
|
151
|
+
scanResult.basename.includes('config') || scanResult.basename.includes('package'),
|
|
152
|
+
scanResult.basename.includes('generated') || scanResult.basename.includes('auto')
|
|
153
|
+
);
|
|
154
|
+
analysis.setTimestamps(
|
|
155
|
+
scanResult.modified,
|
|
156
|
+
scanResult.created
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
fileAnalyses.push(analysis);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (options.verbose) {
|
|
163
|
+
const totalLines = fileAnalyses.reduce((sum, f) => sum + f.lineCount, 0);
|
|
164
|
+
console.log(chalk.gray(`Analyzed ${fileAnalyses.length} files with ${totalLines} total lines`));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return fileAnalyses;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async categorizeFiles(lineResults, options) {
|
|
171
|
+
if (!options.quiet) {
|
|
172
|
+
console.log(chalk.yellow('📂 Categorizing files...'));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const categorizer = new FileCategorizer();
|
|
176
|
+
const fileData = lineResults.map(analysis => ({
|
|
177
|
+
filePath: analysis.filePath,
|
|
178
|
+
lineCount: analysis.lineCount,
|
|
179
|
+
fileType: analysis.extension,
|
|
180
|
+
package: analysis.package
|
|
181
|
+
}));
|
|
182
|
+
|
|
183
|
+
const categorizationResults = categorizer.categorizeFiles(fileData);
|
|
184
|
+
|
|
185
|
+
// Update file analyses with categorization
|
|
186
|
+
for (let i = 0; i < lineResults.length; i++) {
|
|
187
|
+
const analysis = lineResults[i];
|
|
188
|
+
const categorization = categorizationResults.files[i];
|
|
189
|
+
|
|
190
|
+
if (categorization && categorization.categorization) {
|
|
191
|
+
analysis.setClassification(
|
|
192
|
+
categorization.categorization.size,
|
|
193
|
+
categorization.categorization.priority,
|
|
194
|
+
categorization.categorization.difficulty,
|
|
195
|
+
categorization.categorization.needsRefactoring,
|
|
196
|
+
categorization.categorization.urgentRefactoring
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return categorizationResults;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async detectBoundaries(lineResults, options) {
|
|
205
|
+
if (!options.quiet) {
|
|
206
|
+
console.log(chalk.yellow('🔍 Detecting code boundaries...'));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const boundaryDetector = new BoundaryDetector();
|
|
210
|
+
const boundaryResults = new Map();
|
|
211
|
+
|
|
212
|
+
// Only analyze JavaScript/TypeScript files for boundaries
|
|
213
|
+
const jsFiles = lineResults.filter(analysis =>
|
|
214
|
+
['.js', '.jsx', '.ts', '.tsx'].includes(analysis.extension)
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
for (let i = 0; i < jsFiles.length; i++) {
|
|
218
|
+
const analysis = jsFiles[i];
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
const boundaryResult = await boundaryDetector.detectBoundaries(analysis.filePath);
|
|
222
|
+
boundaryResults.set(analysis.filePath, boundaryResult);
|
|
223
|
+
|
|
224
|
+
// Update analysis with boundary data
|
|
225
|
+
analysis.setBoundaries(boundaryResult);
|
|
226
|
+
|
|
227
|
+
if (options.verbose && i % 10 === 0) {
|
|
228
|
+
console.log(chalk.gray(`Analyzed boundaries for ${i + 1}/${jsFiles.length} files`));
|
|
229
|
+
}
|
|
230
|
+
} catch (error) {
|
|
231
|
+
analysis.addError(`Boundary detection failed: ${error.message}`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (options.verbose) {
|
|
236
|
+
console.log(chalk.gray(`Detected boundaries in ${boundaryResults.size} files`));
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return boundaryResults;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async calculatePriorities(lineResults, boundaryResults, options) {
|
|
243
|
+
if (!options.quiet) {
|
|
244
|
+
console.log(chalk.yellow('🎯 Calculating priorities...'));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const priorityCalculator = new PriorityCalculator();
|
|
248
|
+
const priorityResults = priorityCalculator.calculatePriorities(lineResults);
|
|
249
|
+
|
|
250
|
+
// Update file analyses with priority data
|
|
251
|
+
for (let i = 0; i < lineResults.length; i++) {
|
|
252
|
+
const analysis = lineResults[i];
|
|
253
|
+
const priorityResult = priorityResults[i];
|
|
254
|
+
|
|
255
|
+
if (priorityResult) {
|
|
256
|
+
analysis.priority = priorityResult.priority;
|
|
257
|
+
// Add priority reasons as warnings
|
|
258
|
+
for (const reason of priorityResult.reasons) {
|
|
259
|
+
analysis.addWarning(reason);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return priorityResults;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async generateStrategies(lineResults, priorityResults, options) {
|
|
268
|
+
if (!options.quiet) {
|
|
269
|
+
console.log(chalk.yellow('📋 Generating refactoring strategies...'));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Create analysis collection
|
|
273
|
+
const collection = new FileAnalysisCollection();
|
|
274
|
+
for (const analysis of lineResults) {
|
|
275
|
+
collection.add(analysis);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const strategyGenerator = new StrategyGenerator();
|
|
279
|
+
const analysisData = {
|
|
280
|
+
files: lineResults,
|
|
281
|
+
summary: collection.getSummary()
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
const strategies = strategyGenerator.generateStrategies(analysisData);
|
|
285
|
+
|
|
286
|
+
if (options.verbose) {
|
|
287
|
+
console.log(chalk.gray(`Generated ${strategies.length} refactoring strategies`));
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return strategies;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
async generateReport(lineResults, categorizationResults, priorityResults, strategies, options) {
|
|
294
|
+
if (!options.quiet) {
|
|
295
|
+
console.log(chalk.yellow('📊 Generating analysis report...'));
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const reporter = new AnalysisReporter();
|
|
299
|
+
|
|
300
|
+
// Create analysis data for reporter
|
|
301
|
+
const analysisData = {
|
|
302
|
+
files: lineResults,
|
|
303
|
+
summary: {
|
|
304
|
+
totalFiles: lineResults.length,
|
|
305
|
+
filesNeedingRefactoring: lineResults.filter(f => f.needsRefactoring).length,
|
|
306
|
+
urgentRefactoring: lineResults.filter(f => f.urgentRefactoring).length,
|
|
307
|
+
totalLines: lineResults.reduce((sum, f) => sum + f.lineCount, 0)
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const reportOptions = {
|
|
312
|
+
format: options.format,
|
|
313
|
+
outputPath: options.output,
|
|
314
|
+
scope: 'full_codebase',
|
|
315
|
+
packages: [...new Set(lineResults.map(f => f.package))]
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
const reportResult = await reporter.generateReport(analysisData, reportOptions);
|
|
319
|
+
|
|
320
|
+
return {
|
|
321
|
+
reportData: reporter.report,
|
|
322
|
+
exportResult: reportResult,
|
|
323
|
+
strategies,
|
|
324
|
+
summary: analysisData.summary
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
printSummary(results, duration) {
|
|
329
|
+
const { reportData, summary } = results;
|
|
330
|
+
|
|
331
|
+
console.log();
|
|
332
|
+
console.log(chalk.blue('📈 Analysis Summary'));
|
|
333
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
334
|
+
console.log(`📁 Total Files: ${chalk.bold(summary.totalFiles)}`);
|
|
335
|
+
console.log(`📏 Total Lines: ${chalk.bold(summary.totalLines.toLocaleString())}`);
|
|
336
|
+
console.log(`🔧 Files Needing Refactoring: ${chalk.bold(summary.filesNeedingRefactoring)}`);
|
|
337
|
+
console.log(`🚨 Urgent Refactoring: ${chalk.bold(summary.urgentRefactoring)}`);
|
|
338
|
+
console.log(`✅ Compliance Rate: ${chalk.bold(reportData.summary.complianceRate + '%')}`);
|
|
339
|
+
console.log(`🎯 Average Complexity: ${chalk.bold(reportData.summary.averageComplexity)}`);
|
|
340
|
+
console.log(`⏱️ Duration: ${chalk.bold((duration / 1000).toFixed(2) + 's')}`);
|
|
341
|
+
|
|
342
|
+
// Show violations
|
|
343
|
+
if (reportData.violations.length > 0) {
|
|
344
|
+
console.log();
|
|
345
|
+
console.log(chalk.red('⚠️ Violations Found'));
|
|
346
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
347
|
+
|
|
348
|
+
const criticalViolations = reportData.violations.filter(v => v.severity === 'critical');
|
|
349
|
+
const majorViolations = reportData.violations.filter(v => v.severity === 'major');
|
|
350
|
+
|
|
351
|
+
if (criticalViolations.length > 0) {
|
|
352
|
+
console.log(`${chalk.red('🚨 Critical:')} ${criticalViolations.length} files`);
|
|
353
|
+
}
|
|
354
|
+
if (majorViolations.length > 0) {
|
|
355
|
+
console.log(`${chalk.yellow('⚠️ Major:')} ${majorViolations.length} files`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Show top recommendations
|
|
360
|
+
if (reportData.recommendations.length > 0) {
|
|
361
|
+
console.log();
|
|
362
|
+
console.log(chalk.blue('💡 Top Recommendations'));
|
|
363
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
364
|
+
|
|
365
|
+
for (const rec of reportData.recommendations.slice(0, 3)) {
|
|
366
|
+
const priorityColor = rec.priority === 'critical' ? 'red' :
|
|
367
|
+
rec.priority === 'high' ? 'yellow' :
|
|
368
|
+
rec.priority === 'medium' ? 'blue' : 'gray';
|
|
369
|
+
|
|
370
|
+
console.log(`${chalk[priorityColor]('●')} ${rec.title}`);
|
|
371
|
+
console.log(` ${rec.description}`);
|
|
372
|
+
console.log(` Priority: ${rec.priority} | Effort: ${rec.estimatedEffort} units`);
|
|
373
|
+
console.log();
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Package summary
|
|
378
|
+
if (Object.keys(reportData.packageAnalysis).length > 1) {
|
|
379
|
+
console.log(chalk.blue('📦 Package Summary'));
|
|
380
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
381
|
+
|
|
382
|
+
for (const [packageName, packageData] of Object.entries(reportData.packageAnalysis)) {
|
|
383
|
+
const complianceColor = packageData.complianceRate >= 90 ? 'green' :
|
|
384
|
+
packageData.complianceRate >= 70 ? 'yellow' : 'red';
|
|
385
|
+
|
|
386
|
+
console.log(`${packageName}: ${chalk[complianceColor](packageData.complianceRate + '%')} compliant (${packageData.files.length} files)`);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
async saveReport(results, options) {
|
|
392
|
+
try {
|
|
393
|
+
const { exportResult } = results;
|
|
394
|
+
|
|
395
|
+
if (exportResult.success) {
|
|
396
|
+
console.log();
|
|
397
|
+
console.log(chalk.green('✅ Report saved successfully'));
|
|
398
|
+
console.log(chalk.gray(`📄 ${exportResult.path}`));
|
|
399
|
+
|
|
400
|
+
// Show file size
|
|
401
|
+
const stats = fs.statSync(exportResult.path);
|
|
402
|
+
const fileSize = (stats.size / 1024).toFixed(2);
|
|
403
|
+
console.log(chalk.gray(`📊 Size: ${fileSize} KB`));
|
|
404
|
+
} else {
|
|
405
|
+
console.log(chalk.red('❌ Failed to save report'));
|
|
406
|
+
}
|
|
407
|
+
} catch (error) {
|
|
408
|
+
console.error(chalk.red('Error saving report:'), error.message);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Register command with CLI
|
|
415
|
+
*/
|
|
416
|
+
function registerCommand(program) {
|
|
417
|
+
const command = new AnalyzeFileSizesCommand();
|
|
418
|
+
program.addCommand(command.command);
|
|
419
|
+
return command;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Export for direct use
|
|
424
|
+
*/
|
|
425
|
+
module.exports = {
|
|
426
|
+
AnalyzeFileSizesCommand,
|
|
427
|
+
registerCommand
|
|
428
|
+
};
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code processing functions for auto-direct command
|
|
3
|
+
* Extracted from auto-direct.js to reduce file size
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs-extra');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const chalk = require('chalk');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parse search/replace blocks from LLM response
|
|
12
|
+
*/
|
|
13
|
+
function parseSearchReplaceBlocks(response) {
|
|
14
|
+
const changes = [];
|
|
15
|
+
|
|
16
|
+
// Match FILE: path SEARCH: ``` old ``` REPLACE: ``` new ``` format
|
|
17
|
+
const fileBlockRegex = /FILE:\s*(.+?)\s*SEARCH:\s*```[\s\S]*?```[\s\S]*?REPLACE:\s*```[\s\S]*?```/g;
|
|
18
|
+
|
|
19
|
+
let match;
|
|
20
|
+
while ((match = fileBlockRegex.exec(response)) !== null) {
|
|
21
|
+
const fileBlock = match[0];
|
|
22
|
+
const filePath = match[1].trim();
|
|
23
|
+
|
|
24
|
+
// Extract search block
|
|
25
|
+
const searchMatch = fileBlock.match(/SEARCH:\s*```([\s\S]*?)```/);
|
|
26
|
+
// Extract replace block
|
|
27
|
+
const replaceMatch = fileBlock.match(/REPLACE:\s*```([\s\S]*?)```/);
|
|
28
|
+
|
|
29
|
+
if (searchMatch && replaceMatch) {
|
|
30
|
+
changes.push({
|
|
31
|
+
file: filePath,
|
|
32
|
+
search: searchMatch[1].trim(),
|
|
33
|
+
replace: replaceMatch[1].trim()
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return changes;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Normalize whitespace for comparison (convert all whitespace to single spaces)
|
|
43
|
+
*/
|
|
44
|
+
function normalizeWhitespace(str) {
|
|
45
|
+
return str.replace(/\s+/g, ' ').trim();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Extract key identifiers from code (variable names, function names, strings)
|
|
50
|
+
*/
|
|
51
|
+
function extractIdentifiers(code) {
|
|
52
|
+
const identifiers = new Set();
|
|
53
|
+
|
|
54
|
+
// Extract quoted strings
|
|
55
|
+
const stringMatches = code.match(/'([^']+)'/g);
|
|
56
|
+
if (stringMatches) {
|
|
57
|
+
stringMatches.forEach(match => {
|
|
58
|
+
identifiers.add(match.slice(1, -1)); // Remove quotes
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const doubleStringMatches = code.match(/"([^"]+)"/g);
|
|
63
|
+
if (doubleStringMatches) {
|
|
64
|
+
doubleStringMatches.forEach(match => {
|
|
65
|
+
identifiers.add(match.slice(1, -1)); // Remove quotes
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Extract variable/function names (words followed by : or =)
|
|
70
|
+
const nameMatches = code.match(/\b([a-zA-Z_$][a-zA-Z0-9_$]*)\s*[:=]/g);
|
|
71
|
+
if (nameMatches) {
|
|
72
|
+
nameMatches.forEach(match => {
|
|
73
|
+
const name = match.replace(/\s*[:=]/, '');
|
|
74
|
+
identifiers.add(name);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Extract common patterns like 'type:', 'name:', 'value:'
|
|
79
|
+
const patternMatches = code.match(/(type|name|value|file|path|function|const|let|var)\s*:/gi);
|
|
80
|
+
if (patternMatches) {
|
|
81
|
+
patternMatches.forEach(match => {
|
|
82
|
+
identifiers.add(match.toLowerCase().replace(/\s*:/, ''));
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return Array.from(identifiers);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Extract structural pattern from code (ignoring values)
|
|
91
|
+
*/
|
|
92
|
+
function extractPattern(code) {
|
|
93
|
+
// Replace strings with placeholders
|
|
94
|
+
let pattern = code.replace(/'[^']+'|"[^"]+"/g, '"..."');
|
|
95
|
+
// Replace numbers with placeholders
|
|
96
|
+
pattern = pattern.replace(/\b\d+\.?\d*\b/g, '...');
|
|
97
|
+
// Replace whitespace with single spaces
|
|
98
|
+
pattern = normalizeWhitespace(pattern);
|
|
99
|
+
return pattern;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Apply a search/replace change to a file with fuzzy matching fallback
|
|
104
|
+
*/
|
|
105
|
+
async function applyFileChange(change, repoPath) {
|
|
106
|
+
try {
|
|
107
|
+
const fullPath = path.join(repoPath, change.file);
|
|
108
|
+
|
|
109
|
+
if (!await fs.pathExists(fullPath)) {
|
|
110
|
+
console.log(chalk.yellow(`⚠️ File not found: ${change.file}`));
|
|
111
|
+
return { success: false, error: 'File not found' };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const content = await fs.readFile(fullPath, 'utf8');
|
|
115
|
+
const lines = content.split('\n');
|
|
116
|
+
const searchLines = change.search.split('\n');
|
|
117
|
+
|
|
118
|
+
console.log(chalk.gray(` - Search block: ${searchLines.length} lines`));
|
|
119
|
+
console.log(chalk.gray(` - File total: ${lines.length} lines`));
|
|
120
|
+
|
|
121
|
+
// Extract key identifiers from search text (function names, variable names, strings)
|
|
122
|
+
const searchIdentifiers = extractIdentifiers(change.search);
|
|
123
|
+
|
|
124
|
+
// Try multiple window sizes (±5 lines) to account for LLM not including enough context
|
|
125
|
+
const windowSizes = [0, 2, 5, 10, 15];
|
|
126
|
+
|
|
127
|
+
for (const windowSize of windowSizes) {
|
|
128
|
+
// Try to find the search block with fuzzy matching
|
|
129
|
+
let foundIndex = -1;
|
|
130
|
+
|
|
131
|
+
// First try exact match
|
|
132
|
+
const exactMatch = content.indexOf(change.search);
|
|
133
|
+
if (exactMatch !== -1) {
|
|
134
|
+
foundIndex = exactMatch;
|
|
135
|
+
} else {
|
|
136
|
+
// Try fuzzy matching by looking for patterns
|
|
137
|
+
const searchPattern = extractPattern(change.search);
|
|
138
|
+
|
|
139
|
+
for (let i = 0; i <= lines.length - searchLines.length; i++) {
|
|
140
|
+
const window = lines.slice(Math.max(0, i - windowSize),
|
|
141
|
+
Math.min(lines.length, i + searchLines.length + windowSize));
|
|
142
|
+
const windowContent = window.join('\n');
|
|
143
|
+
const windowPattern = extractPattern(windowContent);
|
|
144
|
+
|
|
145
|
+
// Check if patterns match and key identifiers are present
|
|
146
|
+
if (windowPattern.includes(searchPattern) || searchPattern.includes(windowPattern)) {
|
|
147
|
+
const windowIdentifiers = extractIdentifiers(windowContent);
|
|
148
|
+
const commonIdentifiers = searchIdentifiers.filter(id => windowIdentifiers.includes(id));
|
|
149
|
+
|
|
150
|
+
// If we have enough common identifiers, consider it a match
|
|
151
|
+
if (commonIdentifiers.length >= Math.min(3, searchIdentifiers.length)) {
|
|
152
|
+
// Find the actual search block within this window
|
|
153
|
+
const windowStart = Math.max(0, i - windowSize);
|
|
154
|
+
const windowText = lines.slice(windowStart,
|
|
155
|
+
Math.min(lines.length, i + searchLines.length + windowSize)).join('\n');
|
|
156
|
+
|
|
157
|
+
// Try to find the best match within the window
|
|
158
|
+
const bestMatch = findBestMatch(change.search, windowText);
|
|
159
|
+
if (bestMatch.similarity > 0.7) { // 70% similarity threshold
|
|
160
|
+
foundIndex = windowStart + bestMatch.offset;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (foundIndex !== -1) {
|
|
169
|
+
// Calculate line boundaries
|
|
170
|
+
const beforeContent = content.substring(0, foundIndex);
|
|
171
|
+
const afterContent = content.substring(foundIndex);
|
|
172
|
+
const afterLines = afterContent.split('\n');
|
|
173
|
+
|
|
174
|
+
// Find the end of the block to replace
|
|
175
|
+
let endLineIndex = 0;
|
|
176
|
+
let currentLineContent = '';
|
|
177
|
+
|
|
178
|
+
for (let i = 0; i < afterLines.length; i++) {
|
|
179
|
+
currentLineContent += (i > 0 ? '\n' : '') + afterLines[i];
|
|
180
|
+
|
|
181
|
+
// Check if we've found a block that matches our search
|
|
182
|
+
const testContent = afterLines.slice(0, i + 1).join('\n');
|
|
183
|
+
const similarity = calculateSimilarity(change.search, testContent);
|
|
184
|
+
|
|
185
|
+
if (similarity > 0.8 || i >= searchLines.length + 5) { // Allow some extra lines
|
|
186
|
+
endLineIndex = i + 1;
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Replace the content
|
|
192
|
+
const newContent = beforeContent + change.replace +
|
|
193
|
+
afterLines.slice(endLineIndex).join('\n');
|
|
194
|
+
|
|
195
|
+
await fs.writeFile(fullPath, newContent);
|
|
196
|
+
|
|
197
|
+
console.log(chalk.green(` ✅ Applied change to ${change.file}`));
|
|
198
|
+
return { success: true };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
console.log(chalk.yellow(` ⚠️ Could not find matching block in ${change.file}`));
|
|
203
|
+
return { success: false, error: 'Could not find matching block' };
|
|
204
|
+
|
|
205
|
+
} catch (error) {
|
|
206
|
+
console.error(chalk.red(` ❌ Error applying change to ${change.file}:`), error.message);
|
|
207
|
+
return { success: false, error: error.message };
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Find best match within a text block
|
|
213
|
+
*/
|
|
214
|
+
function findBestMatch(searchText, textBlock) {
|
|
215
|
+
const searchLines = searchText.split('\n');
|
|
216
|
+
const textLines = textBlock.split('\n');
|
|
217
|
+
|
|
218
|
+
let bestMatch = { similarity: 0, offset: 0 };
|
|
219
|
+
|
|
220
|
+
for (let offset = 0; offset <= textLines.length - searchLines.length; offset++) {
|
|
221
|
+
const testBlock = textLines.slice(offset, offset + searchLines.length).join('\n');
|
|
222
|
+
const similarity = calculateSimilarity(searchText, testBlock);
|
|
223
|
+
|
|
224
|
+
if (similarity > bestMatch.similarity) {
|
|
225
|
+
bestMatch = { similarity, offset };
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return bestMatch;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Calculate similarity between two strings
|
|
234
|
+
*/
|
|
235
|
+
function calculateSimilarity(str1, str2) {
|
|
236
|
+
const longer = str1.length > str2.length ? str1 : str2;
|
|
237
|
+
const shorter = str1.length > str2.length ? str2 : str1;
|
|
238
|
+
|
|
239
|
+
if (longer.length === 0) return 1.0;
|
|
240
|
+
|
|
241
|
+
const editDistance = levenshteinDistance(longer, shorter);
|
|
242
|
+
return (longer.length - editDistance) / longer.length;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Calculate Levenshtein distance between two strings
|
|
247
|
+
*/
|
|
248
|
+
function levenshteinDistance(str1, str2) {
|
|
249
|
+
const matrix = [];
|
|
250
|
+
|
|
251
|
+
for (let i = 0; i <= str2.length; i++) {
|
|
252
|
+
matrix[i] = [i];
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
for (let j = 0; j <= str1.length; j++) {
|
|
256
|
+
matrix[0][j] = j;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
for (let i = 1; i <= str2.length; i++) {
|
|
260
|
+
for (let j = 1; j <= str1.length; j++) {
|
|
261
|
+
if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
|
|
262
|
+
matrix[i][j] = matrix[i - 1][j - 1];
|
|
263
|
+
} else {
|
|
264
|
+
matrix[i][j] = Math.min(
|
|
265
|
+
matrix[i - 1][j - 1] + 1,
|
|
266
|
+
matrix[i][j - 1] + 1,
|
|
267
|
+
matrix[i - 1][j] + 1
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return matrix[str2.length][str1.length];
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
module.exports = {
|
|
277
|
+
parseSearchReplaceBlocks,
|
|
278
|
+
normalizeWhitespace,
|
|
279
|
+
extractIdentifiers,
|
|
280
|
+
extractPattern,
|
|
281
|
+
applyFileChange
|
|
282
|
+
};
|