fscr 6.2.6 → 7.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.
- package/README.md +48 -30
- package/dist/index.js +502 -186
- package/dist/lib/auth/auth-conf.js +49 -45
- package/dist/lib/cache/README.md +341 -0
- package/dist/lib/cache/cli.js +152 -0
- package/dist/lib/cache/file-watcher.js +193 -0
- package/dist/lib/cache/index.js +422 -0
- package/dist/lib/cache/monitor.js +224 -0
- package/dist/lib/commands/doctor.js +225 -0
- package/dist/lib/completions/completion.js +342 -0
- package/dist/lib/completions/generator.js +152 -0
- package/dist/lib/completions/scripts/bash.sh +108 -0
- package/dist/lib/completions/scripts/fish.sh +105 -0
- package/dist/lib/completions/scripts/powershell.ps1 +168 -0
- package/dist/lib/completions/scripts/zsh.sh +124 -0
- package/dist/lib/diagnostics/cache.js +121 -0
- package/dist/lib/diagnostics/fileSystem.js +236 -0
- package/dist/lib/diagnostics/gitCheck.js +41 -0
- package/dist/lib/diagnostics/nodeVersion.js +68 -0
- package/dist/lib/diagnostics/packageManager.js +64 -0
- package/dist/lib/diagnostics/performance.js +141 -0
- package/dist/lib/encryption/decryptConfig.js +3 -2
- package/dist/lib/encryption/encryption.js +153 -113
- package/dist/lib/generators/generateFScripts.js +16 -13
- package/dist/lib/generators/generateToc.js +23 -14
- package/dist/lib/generators/index.js +1 -1
- package/dist/lib/git/pub.js +27 -17
- package/dist/lib/git/taskRunner.js +79 -69
- package/dist/lib/git/validateNotDev.js +65 -54
- package/dist/lib/optionList.js +69 -57
- package/dist/lib/parsers/parseScriptsMd.cached.js +208 -0
- package/dist/lib/parsers/parseScriptsMd.js +88 -79
- package/dist/lib/parsers/parseScriptsPackage.js +4 -3
- package/dist/lib/performance/cache.js +199 -0
- package/dist/lib/performance/lazy-loader.js +189 -0
- package/dist/lib/performance/monitor.js +303 -0
- package/dist/lib/plugins/deployment/index.js +113 -0
- package/dist/lib/plugins/hooks.js +17 -0
- package/dist/lib/plugins/loader.js +91 -0
- package/dist/lib/plugins/task-notifier/index.js +72 -0
- package/dist/lib/release/bump.js +50 -45
- package/dist/lib/release/commitWithMessage.js +80 -52
- package/dist/lib/release/publish.js +19 -14
- package/dist/lib/release/pushToGit.js +40 -31
- package/dist/lib/release/releasenotes.js +116 -97
- package/dist/lib/release/seeChangedFiles.js +68 -60
- package/dist/lib/release/sort.js +200 -116
- package/dist/lib/release/tree.js +161 -147
- package/dist/lib/release/validateNotDev.js +52 -44
- package/dist/lib/running/index.js +1 -1
- package/dist/lib/running/runCLICommand.js +41 -31
- package/dist/lib/running/runParallel.js +61 -59
- package/dist/lib/running/runSequence.js +55 -53
- package/dist/lib/startScripts.js +129 -114
- package/dist/lib/taskList.js +97 -90
- package/dist/lib/test-files/.fscripts.md +113 -0
- package/dist/lib/test-files/.fscripts.test.md +103 -0
- package/dist/lib/test-files/.fscriptsb.md +107 -0
- package/dist/lib/test-files/.mdtest.md +40 -0
- package/dist/lib/test-files/consoleSample.js +13 -9
- package/dist/lib/test-files/inputSample.js +17 -14
- package/dist/lib/test-files/testConsole.js +1 -1
- package/dist/lib/test-files/testInput.js +1 -1
- package/dist/lib/upgradePackages.js +56 -46
- package/dist/lib/utils/clear.js +16 -13
- package/dist/lib/utils/console.js +27 -21
- package/dist/lib/utils/encryption.js +55 -13
- package/dist/lib/utils/hash.js +128 -0
- package/dist/lib/utils/helpers.js +153 -142
- package/dist/lib/utils/index.js +1 -1
- package/dist/lib/utils/prompt.js +24 -29
- package/package.json +11 -29
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache monitoring and statistics
|
|
3
|
+
* @module cache/monitor
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* CacheMonitor - Collects and displays cache performance metrics
|
|
10
|
+
* @class
|
|
11
|
+
*/
|
|
12
|
+
class CacheMonitor {
|
|
13
|
+
/**
|
|
14
|
+
* Create a cache monitor
|
|
15
|
+
* @param {CacheManager} cacheManager - Cache manager instance
|
|
16
|
+
* @param {FileWatcher} [fileWatcher] - Optional file watcher instance
|
|
17
|
+
*/
|
|
18
|
+
constructor(cacheManager, fileWatcher = null) {
|
|
19
|
+
this.cacheManager = cacheManager;
|
|
20
|
+
this.fileWatcher = fileWatcher;
|
|
21
|
+
|
|
22
|
+
// Performance tracking
|
|
23
|
+
this.metrics = {
|
|
24
|
+
coldCacheTime: [],
|
|
25
|
+
warmCacheTime: [],
|
|
26
|
+
avgColdTime: 0,
|
|
27
|
+
avgWarmTime: 0,
|
|
28
|
+
speedup: 0
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Listen to cache events
|
|
32
|
+
this._attachListeners();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Attach event listeners to cache manager
|
|
37
|
+
* @private
|
|
38
|
+
*/
|
|
39
|
+
_attachListeners() {
|
|
40
|
+
this.cacheManager.on('hit', () => {
|
|
41
|
+
// Cache hit event
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
this.cacheManager.on('miss', () => {
|
|
45
|
+
// Cache miss event
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
this.cacheManager.on('invalidate', ({ key }) => {
|
|
49
|
+
// Invalidation event
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
this.cacheManager.on('evict', ({ key }) => {
|
|
53
|
+
// Eviction event
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
this.cacheManager.on('cleanup', ({ count }) => {
|
|
57
|
+
// Cleanup event
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Record a cold cache operation time
|
|
63
|
+
* @param {number} timeMs - Time in milliseconds
|
|
64
|
+
*/
|
|
65
|
+
recordColdCache(timeMs) {
|
|
66
|
+
this.metrics.coldCacheTime.push(timeMs);
|
|
67
|
+
this._updateAverages();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Record a warm cache operation time
|
|
72
|
+
* @param {number} timeMs - Time in milliseconds
|
|
73
|
+
*/
|
|
74
|
+
recordWarmCache(timeMs) {
|
|
75
|
+
this.metrics.warmCacheTime.push(timeMs);
|
|
76
|
+
this._updateAverages();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Update average times and speedup
|
|
81
|
+
* @private
|
|
82
|
+
*/
|
|
83
|
+
_updateAverages() {
|
|
84
|
+
if (this.metrics.coldCacheTime.length > 0) {
|
|
85
|
+
const sum = this.metrics.coldCacheTime.reduce((a, b) => a + b, 0);
|
|
86
|
+
this.metrics.avgColdTime = sum / this.metrics.coldCacheTime.length;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (this.metrics.warmCacheTime.length > 0) {
|
|
90
|
+
const sum = this.metrics.warmCacheTime.reduce((a, b) => a + b, 0);
|
|
91
|
+
this.metrics.avgWarmTime = sum / this.metrics.warmCacheTime.length;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (this.metrics.avgWarmTime > 0 && this.metrics.avgColdTime > 0) {
|
|
95
|
+
this.metrics.speedup = this.metrics.avgColdTime / this.metrics.avgWarmTime;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Get comprehensive statistics
|
|
101
|
+
* @returns {Object} Statistics object
|
|
102
|
+
*/
|
|
103
|
+
getStats() {
|
|
104
|
+
const cacheStats = this.cacheManager.getStats();
|
|
105
|
+
const watcherStats = this.fileWatcher ? this.fileWatcher.getStats() : null;
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
cache: cacheStats,
|
|
109
|
+
watcher: watcherStats,
|
|
110
|
+
performance: {
|
|
111
|
+
avgColdTime: Math.round(this.metrics.avgColdTime),
|
|
112
|
+
avgWarmTime: Math.round(this.metrics.avgWarmTime),
|
|
113
|
+
speedup: this.metrics.speedup.toFixed(2) + 'x',
|
|
114
|
+
coldCacheSamples: this.metrics.coldCacheTime.length,
|
|
115
|
+
warmCacheSamples: this.metrics.warmCacheTime.length
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Print statistics to console
|
|
122
|
+
* @param {Object} [options] - Display options
|
|
123
|
+
* @param {boolean} [options.verbose=false] - Show detailed stats
|
|
124
|
+
*/
|
|
125
|
+
printStats(options = {}) {
|
|
126
|
+
const verbose = options.verbose || false;
|
|
127
|
+
const stats = this.getStats();
|
|
128
|
+
|
|
129
|
+
console.log('\n' + chalk.bold.cyan('=== Cache Statistics ==='));
|
|
130
|
+
|
|
131
|
+
// Cache stats
|
|
132
|
+
console.log(chalk.bold('\nCache:'));
|
|
133
|
+
console.log(` Size: ${chalk.green(stats.cache.size)}/${stats.cache.maxSize}`);
|
|
134
|
+
console.log(` Hits: ${chalk.green(stats.cache.hits)}`);
|
|
135
|
+
console.log(` Misses: ${chalk.yellow(stats.cache.misses)}`);
|
|
136
|
+
console.log(` Hit Rate: ${this._colorizeHitRate(stats.cache.hitRate)}%`);
|
|
137
|
+
console.log(` Invalidations: ${chalk.yellow(stats.cache.invalidations)}`);
|
|
138
|
+
console.log(` Evictions: ${chalk.yellow(stats.cache.evictions)}`);
|
|
139
|
+
|
|
140
|
+
// Performance stats
|
|
141
|
+
if (stats.performance.warmCacheSamples > 0) {
|
|
142
|
+
console.log(chalk.bold('\nPerformance:'));
|
|
143
|
+
console.log(` Cold Cache: ${chalk.yellow(stats.performance.avgColdTime + 'ms')}`);
|
|
144
|
+
console.log(` Warm Cache: ${chalk.green(stats.performance.avgWarmTime + 'ms')}`);
|
|
145
|
+
console.log(` Speedup: ${chalk.bold.green(stats.performance.speedup)}`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// File watcher stats
|
|
149
|
+
if (stats.watcher) {
|
|
150
|
+
console.log(chalk.bold('\nFile Watcher:'));
|
|
151
|
+
console.log(` Files Watched: ${chalk.green(stats.watcher.filesWatched)}`);
|
|
152
|
+
console.log(` Change Events: ${chalk.yellow(stats.watcher.changeEvents)}`);
|
|
153
|
+
console.log(` Invalidations: ${chalk.yellow(stats.watcher.invalidations)}`);
|
|
154
|
+
|
|
155
|
+
if (verbose && stats.watcher.watchedFiles.length > 0) {
|
|
156
|
+
console.log(chalk.bold('\n Watched Files:'));
|
|
157
|
+
stats.watcher.watchedFiles.forEach(file => {
|
|
158
|
+
console.log(` - ${chalk.gray(file)}`);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Uptime
|
|
164
|
+
const uptimeMinutes = Math.floor(stats.cache.uptime / 60000);
|
|
165
|
+
console.log(chalk.bold('\nUptime:'), chalk.green(`${uptimeMinutes} minutes`));
|
|
166
|
+
|
|
167
|
+
console.log(chalk.bold.cyan('\n========================\n'));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Colorize hit rate based on percentage
|
|
172
|
+
* @private
|
|
173
|
+
* @param {string|number} hitRate - Hit rate percentage
|
|
174
|
+
* @returns {string} Colored hit rate
|
|
175
|
+
*/
|
|
176
|
+
_colorizeHitRate(hitRate) {
|
|
177
|
+
const rate = parseFloat(hitRate);
|
|
178
|
+
if (rate >= 80) return chalk.green(hitRate);
|
|
179
|
+
if (rate >= 50) return chalk.yellow(hitRate);
|
|
180
|
+
return chalk.red(hitRate);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Get summary statistics as a single line
|
|
185
|
+
* @returns {string} Summary string
|
|
186
|
+
*/
|
|
187
|
+
getSummary() {
|
|
188
|
+
const stats = this.getStats();
|
|
189
|
+
const parts = [
|
|
190
|
+
`${stats.cache.size} entries`,
|
|
191
|
+
`${stats.cache.hitRate}% hit rate`
|
|
192
|
+
];
|
|
193
|
+
|
|
194
|
+
if (stats.performance.warmCacheSamples > 0) {
|
|
195
|
+
parts.push(`${stats.performance.speedup} speedup`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return parts.join(', ');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Export statistics as JSON
|
|
203
|
+
* @returns {string} JSON string
|
|
204
|
+
*/
|
|
205
|
+
toJSON() {
|
|
206
|
+
return JSON.stringify(this.getStats(), null, 2);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Reset all metrics
|
|
211
|
+
*/
|
|
212
|
+
resetMetrics() {
|
|
213
|
+
this.metrics = {
|
|
214
|
+
coldCacheTime: [],
|
|
215
|
+
warmCacheTime: [],
|
|
216
|
+
avgColdTime: 0,
|
|
217
|
+
avgWarmTime: 0,
|
|
218
|
+
speedup: 0
|
|
219
|
+
};
|
|
220
|
+
this.cacheManager.resetStats();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export default CacheMonitor;
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import boxen from 'boxen';
|
|
3
|
+
import { checkNodeVersion } from '../diagnostics/nodeVersion.js';
|
|
4
|
+
import { checkPackageManager } from '../diagnostics/packageManager.js';
|
|
5
|
+
import { checkGit } from '../diagnostics/gitCheck.js';
|
|
6
|
+
import {
|
|
7
|
+
checkFScriptsFile,
|
|
8
|
+
checkPackageJson,
|
|
9
|
+
checkTypeScript,
|
|
10
|
+
checkFilePermissions
|
|
11
|
+
} from '../diagnostics/fileSystem.js';
|
|
12
|
+
import { checkCache } from '../diagnostics/cache.js';
|
|
13
|
+
import { checkStartupTime, checkMemoryUsage } from '../diagnostics/performance.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Run all diagnostic checks
|
|
17
|
+
* @param {Object} options - Command options
|
|
18
|
+
* @returns {Promise<Object>} Results object
|
|
19
|
+
*/
|
|
20
|
+
export async function runDiagnostics(options = {}) {
|
|
21
|
+
const { fix = false, json = false } = options;
|
|
22
|
+
|
|
23
|
+
console.log(chalk.cyan.bold('\n🔍 Running FSCR diagnostics...\n'));
|
|
24
|
+
|
|
25
|
+
const checks = [
|
|
26
|
+
{ name: 'nodeVersion', fn: checkNodeVersion, critical: true },
|
|
27
|
+
{ name: 'packageManager', fn: checkPackageManager, critical: true },
|
|
28
|
+
{ name: 'git', fn: checkGit, critical: false },
|
|
29
|
+
{ name: 'fscriptsFile', fn: checkFScriptsFile, critical: false },
|
|
30
|
+
{ name: 'packageJson', fn: checkPackageJson, critical: true },
|
|
31
|
+
{ name: 'typescript', fn: checkTypeScript, critical: false },
|
|
32
|
+
{ name: 'filePermissions', fn: checkFilePermissions, critical: true },
|
|
33
|
+
{ name: 'cache', fn: checkCache, critical: false },
|
|
34
|
+
{ name: 'startupTime', fn: checkStartupTime, critical: false },
|
|
35
|
+
{ name: 'memoryUsage', fn: checkMemoryUsage, critical: false }
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
const results = [];
|
|
39
|
+
let passedCount = 0;
|
|
40
|
+
let warningCount = 0;
|
|
41
|
+
let errorCount = 0;
|
|
42
|
+
let fixedCount = 0;
|
|
43
|
+
|
|
44
|
+
for (const check of checks) {
|
|
45
|
+
try {
|
|
46
|
+
const result = await check.fn();
|
|
47
|
+
results.push({ ...result, critical: check.critical });
|
|
48
|
+
|
|
49
|
+
// Display result
|
|
50
|
+
displayCheckResult(result);
|
|
51
|
+
|
|
52
|
+
// Count results
|
|
53
|
+
if (result.passed && !result.warning) {
|
|
54
|
+
passedCount++;
|
|
55
|
+
} else if (result.warning) {
|
|
56
|
+
warningCount++;
|
|
57
|
+
} else {
|
|
58
|
+
errorCount++;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Auto-fix if requested
|
|
62
|
+
if (fix && !result.passed && result.canFix && result.fix) {
|
|
63
|
+
try {
|
|
64
|
+
console.log(chalk.yellow(` Attempting to fix...`));
|
|
65
|
+
const fixMessage = await result.fix();
|
|
66
|
+
console.log(chalk.green(` ✓ Fixed: ${fixMessage}\n`));
|
|
67
|
+
fixedCount++;
|
|
68
|
+
} catch (fixError) {
|
|
69
|
+
console.log(chalk.red(` ✗ Fix failed: ${fixError.message}\n`));
|
|
70
|
+
}
|
|
71
|
+
} else if (!result.passed && result.fixInstructions) {
|
|
72
|
+
console.log(chalk.gray(` ${result.fixInstructions}\n`));
|
|
73
|
+
}
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.log(
|
|
76
|
+
chalk.red(`❌ ${check.name}\n Error: ${error.message}\n`)
|
|
77
|
+
);
|
|
78
|
+
errorCount++;
|
|
79
|
+
results.push({
|
|
80
|
+
name: check.name,
|
|
81
|
+
passed: false,
|
|
82
|
+
error: error.message,
|
|
83
|
+
critical: check.critical
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Display summary (skip if JSON mode)
|
|
89
|
+
if (!json) {
|
|
90
|
+
displaySummary(passedCount, warningCount, errorCount, fixedCount);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Return results object
|
|
94
|
+
return {
|
|
95
|
+
passed: errorCount === 0,
|
|
96
|
+
summary: {
|
|
97
|
+
passed: passedCount,
|
|
98
|
+
warnings: warningCount,
|
|
99
|
+
errors: errorCount,
|
|
100
|
+
fixed: fixedCount,
|
|
101
|
+
total: checks.length
|
|
102
|
+
},
|
|
103
|
+
results
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Display check result
|
|
109
|
+
* @param {Object} result - Check result
|
|
110
|
+
*/
|
|
111
|
+
function displayCheckResult(result) {
|
|
112
|
+
let icon = '✅';
|
|
113
|
+
let color = 'green';
|
|
114
|
+
|
|
115
|
+
if (!result.passed) {
|
|
116
|
+
icon = '❌';
|
|
117
|
+
color = 'red';
|
|
118
|
+
} else if (result.warning) {
|
|
119
|
+
icon = '⚠️ ';
|
|
120
|
+
color = 'yellow';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
console.log(chalk[color](`${icon} ${result.name}`));
|
|
124
|
+
console.log(chalk.gray(` ${result.message}\n`));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Display summary
|
|
129
|
+
* @param {number} passed - Number of passed checks
|
|
130
|
+
* @param {number} warnings - Number of warnings
|
|
131
|
+
* @param {number} errors - Number of errors
|
|
132
|
+
* @param {number} fixed - Number of fixed issues
|
|
133
|
+
*/
|
|
134
|
+
function displaySummary(passed, warnings, errors, fixed) {
|
|
135
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
136
|
+
console.log(chalk.bold('Summary:'));
|
|
137
|
+
|
|
138
|
+
if (passed > 0) {
|
|
139
|
+
console.log(chalk.green(` ✅ Passed: ${passed}`));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (warnings > 0) {
|
|
143
|
+
console.log(chalk.yellow(` ⚠️ Warnings: ${warnings}`));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (errors > 0) {
|
|
147
|
+
console.log(chalk.red(` ❌ Errors: ${errors}`));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (fixed > 0) {
|
|
151
|
+
console.log(chalk.cyan(` 🔧 Fixed: ${fixed}`));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
155
|
+
|
|
156
|
+
// Overall status
|
|
157
|
+
if (errors === 0 && warnings === 0) {
|
|
158
|
+
console.log(
|
|
159
|
+
boxen(chalk.green.bold('✓ All checks passed!'), {
|
|
160
|
+
padding: 1,
|
|
161
|
+
margin: 1,
|
|
162
|
+
borderStyle: 'round',
|
|
163
|
+
borderColor: 'green'
|
|
164
|
+
})
|
|
165
|
+
);
|
|
166
|
+
} else if (errors === 0) {
|
|
167
|
+
console.log(
|
|
168
|
+
boxen(chalk.yellow.bold('⚠ System operational with warnings'), {
|
|
169
|
+
padding: 1,
|
|
170
|
+
margin: 1,
|
|
171
|
+
borderStyle: 'round',
|
|
172
|
+
borderColor: 'yellow'
|
|
173
|
+
})
|
|
174
|
+
);
|
|
175
|
+
} else {
|
|
176
|
+
console.log(
|
|
177
|
+
boxen(chalk.red.bold('✗ Issues found - please review above'), {
|
|
178
|
+
padding: 1,
|
|
179
|
+
margin: 1,
|
|
180
|
+
borderStyle: 'round',
|
|
181
|
+
borderColor: 'red'
|
|
182
|
+
})
|
|
183
|
+
);
|
|
184
|
+
console.log(
|
|
185
|
+
chalk.gray(
|
|
186
|
+
'\nTip: Run "fsr doctor --fix" to automatically fix some issues\n'
|
|
187
|
+
)
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Doctor command handler
|
|
194
|
+
* @param {Object} argv - Command arguments
|
|
195
|
+
*/
|
|
196
|
+
export default async function doctor(argv) {
|
|
197
|
+
try {
|
|
198
|
+
const options = {
|
|
199
|
+
fix: argv.fix || false,
|
|
200
|
+
json: argv.json || false
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const result = await runDiagnostics(options);
|
|
204
|
+
|
|
205
|
+
if (options.json) {
|
|
206
|
+
console.log(JSON.stringify(result, null, 2));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Exit with error code if there are critical failures
|
|
210
|
+
if (!result.passed) {
|
|
211
|
+
const criticalFailures = result.results.filter(
|
|
212
|
+
(r) => !r.passed && r.critical
|
|
213
|
+
);
|
|
214
|
+
if (criticalFailures.length > 0) {
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
} catch (error) {
|
|
219
|
+
console.error(chalk.red.bold(`\n❌ Doctor command failed: ${error.message}\n`));
|
|
220
|
+
if (argv.verbose) {
|
|
221
|
+
console.error(error.stack);
|
|
222
|
+
}
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
}
|