forgestack-os-cli 0.3.4 → 0.3.6
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 +382 -150
- package/dist/commands/doctor.d.ts +12 -0
- package/dist/commands/doctor.js +214 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/organize.d.ts +2 -0
- package/dist/commands/organize.js +126 -0
- package/dist/commands/organize.js.map +1 -0
- package/dist/commands/run-tasks.d.ts +12 -0
- package/dist/commands/run-tasks.js +125 -0
- package/dist/commands/run-tasks.js.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/doctor/check-database.d.ts +8 -0
- package/dist/utils/doctor/check-database.js +271 -0
- package/dist/utils/doctor/check-database.js.map +1 -0
- package/dist/utils/doctor/check-docker.d.ts +8 -0
- package/dist/utils/doctor/check-docker.js +212 -0
- package/dist/utils/doctor/check-docker.js.map +1 -0
- package/dist/utils/doctor/check-env.d.ts +12 -0
- package/dist/utils/doctor/check-env.js +207 -0
- package/dist/utils/doctor/check-env.js.map +1 -0
- package/dist/utils/doctor/check-lint.d.ts +8 -0
- package/dist/utils/doctor/check-lint.js +225 -0
- package/dist/utils/doctor/check-lint.js.map +1 -0
- package/dist/utils/doctor/check-node.d.ts +20 -0
- package/dist/utils/doctor/check-node.js +172 -0
- package/dist/utils/doctor/check-node.js.map +1 -0
- package/dist/utils/doctor/check-ports.d.ts +15 -0
- package/dist/utils/doctor/check-ports.js +166 -0
- package/dist/utils/doctor/check-ports.js.map +1 -0
- package/dist/utils/doctor/check-prisma.d.ts +8 -0
- package/dist/utils/doctor/check-prisma.js +202 -0
- package/dist/utils/doctor/check-prisma.js.map +1 -0
- package/dist/utils/doctor/index.d.ts +14 -0
- package/dist/utils/doctor/index.js +15 -0
- package/dist/utils/doctor/index.js.map +1 -0
- package/dist/utils/doctor/types.d.ts +50 -0
- package/dist/utils/doctor/types.js +5 -0
- package/dist/utils/doctor/types.js.map +1 -0
- package/dist/utils/file-organizer.d.ts +17 -0
- package/dist/utils/file-organizer.js +170 -0
- package/dist/utils/file-organizer.js.map +1 -0
- package/dist/utils/task-runner.d.ts +14 -0
- package/dist/utils/task-runner.js +79 -0
- package/dist/utils/task-runner.js.map +1 -0
- package/package.json +11 -4
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment variable validation checks
|
|
3
|
+
*/
|
|
4
|
+
import fs from 'fs-extra';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
/**
|
|
7
|
+
* Parse .env file content into key-value pairs
|
|
8
|
+
*/
|
|
9
|
+
function parseEnvFile(content) {
|
|
10
|
+
const env = {};
|
|
11
|
+
const lines = content.split('\n');
|
|
12
|
+
for (const line of lines) {
|
|
13
|
+
const trimmed = line.trim();
|
|
14
|
+
// Skip comments and empty lines
|
|
15
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
16
|
+
continue;
|
|
17
|
+
const match = trimmed.match(/^([^=]+)=(.*)$/);
|
|
18
|
+
if (match) {
|
|
19
|
+
const key = match[1].trim();
|
|
20
|
+
let value = match[2].trim();
|
|
21
|
+
// Remove quotes if present
|
|
22
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
23
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
24
|
+
value = value.slice(1, -1);
|
|
25
|
+
}
|
|
26
|
+
env[key] = value;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return env;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Infer the type of an environment variable from its example value
|
|
33
|
+
*/
|
|
34
|
+
function inferEnvType(name, exampleValue) {
|
|
35
|
+
const lowerName = name.toLowerCase();
|
|
36
|
+
// URL detection
|
|
37
|
+
if (lowerName.includes('url') || lowerName.includes('uri') ||
|
|
38
|
+
lowerName.includes('endpoint') || lowerName.includes('host') ||
|
|
39
|
+
exampleValue.startsWith('http://') || exampleValue.startsWith('https://') ||
|
|
40
|
+
exampleValue.startsWith('postgres://') || exampleValue.startsWith('mongodb://') ||
|
|
41
|
+
exampleValue.startsWith('mysql://')) {
|
|
42
|
+
return 'url';
|
|
43
|
+
}
|
|
44
|
+
// Boolean detection
|
|
45
|
+
if (exampleValue.toLowerCase() === 'true' || exampleValue.toLowerCase() === 'false' ||
|
|
46
|
+
exampleValue === '0' || exampleValue === '1') {
|
|
47
|
+
return 'boolean';
|
|
48
|
+
}
|
|
49
|
+
// Number detection
|
|
50
|
+
if (lowerName.includes('port') || lowerName.includes('timeout') ||
|
|
51
|
+
lowerName.includes('limit') || lowerName.includes('size') ||
|
|
52
|
+
lowerName.includes('count') || lowerName.includes('max') ||
|
|
53
|
+
lowerName.includes('min') || /^\d+$/.test(exampleValue)) {
|
|
54
|
+
return 'number';
|
|
55
|
+
}
|
|
56
|
+
return 'string';
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Validate a value against its expected type
|
|
60
|
+
*/
|
|
61
|
+
function validateEnvValue(value, type) {
|
|
62
|
+
if (!value)
|
|
63
|
+
return false;
|
|
64
|
+
switch (type) {
|
|
65
|
+
case 'number':
|
|
66
|
+
return !isNaN(Number(value)) && value.trim() !== '';
|
|
67
|
+
case 'boolean':
|
|
68
|
+
return ['true', 'false', '0', '1', 'yes', 'no'].includes(value.toLowerCase());
|
|
69
|
+
case 'url':
|
|
70
|
+
try {
|
|
71
|
+
new URL(value);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// Also accept connection strings with protocols
|
|
76
|
+
return /^[a-z]+:\/\/.+/.test(value);
|
|
77
|
+
}
|
|
78
|
+
case 'string':
|
|
79
|
+
default:
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Check environment variables against .env.example
|
|
85
|
+
*/
|
|
86
|
+
export async function checkEnvVariables(cwd) {
|
|
87
|
+
const results = [];
|
|
88
|
+
const envExamplePath = path.join(cwd, '.env.example');
|
|
89
|
+
const envPath = path.join(cwd, '.env');
|
|
90
|
+
// Check if .env.example exists
|
|
91
|
+
if (!await fs.pathExists(envExamplePath)) {
|
|
92
|
+
results.push({
|
|
93
|
+
name: 'Environment Variables',
|
|
94
|
+
status: 'skip',
|
|
95
|
+
message: 'No .env.example found',
|
|
96
|
+
details: 'Create a .env.example file to enable environment variable validation',
|
|
97
|
+
});
|
|
98
|
+
return results;
|
|
99
|
+
}
|
|
100
|
+
// Read .env.example
|
|
101
|
+
const exampleContent = await fs.readFile(envExamplePath, 'utf-8');
|
|
102
|
+
const exampleVars = parseEnvFile(exampleContent);
|
|
103
|
+
if (Object.keys(exampleVars).length === 0) {
|
|
104
|
+
results.push({
|
|
105
|
+
name: 'Environment Variables',
|
|
106
|
+
status: 'skip',
|
|
107
|
+
message: '.env.example is empty',
|
|
108
|
+
});
|
|
109
|
+
return results;
|
|
110
|
+
}
|
|
111
|
+
// Check if .env exists
|
|
112
|
+
if (!await fs.pathExists(envPath)) {
|
|
113
|
+
const missingVars = Object.keys(exampleVars);
|
|
114
|
+
results.push({
|
|
115
|
+
name: 'Environment Variables',
|
|
116
|
+
status: 'fail',
|
|
117
|
+
message: `.env file not found (${missingVars.length} variables required)`,
|
|
118
|
+
details: `Missing: ${missingVars.join(', ')}`,
|
|
119
|
+
fix: 'Copy .env.example to .env and fill in the values',
|
|
120
|
+
});
|
|
121
|
+
return results;
|
|
122
|
+
}
|
|
123
|
+
// Read .env
|
|
124
|
+
const envContent = await fs.readFile(envPath, 'utf-8');
|
|
125
|
+
const envVars = parseEnvFile(envContent);
|
|
126
|
+
// Check for missing variables
|
|
127
|
+
const missingVars = [];
|
|
128
|
+
const invalidVars = [];
|
|
129
|
+
for (const [name, exampleValue] of Object.entries(exampleVars)) {
|
|
130
|
+
const currentValue = envVars[name];
|
|
131
|
+
if (currentValue === undefined || currentValue === '') {
|
|
132
|
+
missingVars.push(name);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
// Validate type
|
|
136
|
+
const expectedType = inferEnvType(name, exampleValue);
|
|
137
|
+
if (!validateEnvValue(currentValue, expectedType)) {
|
|
138
|
+
invalidVars.push({ name, expectedType });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// Report missing variables
|
|
143
|
+
if (missingVars.length > 0) {
|
|
144
|
+
results.push({
|
|
145
|
+
name: 'Missing .env Variables',
|
|
146
|
+
status: 'fail',
|
|
147
|
+
message: `${missingVars.length} environment variable(s) missing`,
|
|
148
|
+
details: missingVars.join(', '),
|
|
149
|
+
fix: 'Add the missing variables to your .env file',
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
results.push({
|
|
154
|
+
name: 'Environment Variables',
|
|
155
|
+
status: 'pass',
|
|
156
|
+
message: 'All required environment variables are set',
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
// Report invalid type variables
|
|
160
|
+
if (invalidVars.length > 0) {
|
|
161
|
+
results.push({
|
|
162
|
+
name: 'Environment Variable Types',
|
|
163
|
+
status: 'warn',
|
|
164
|
+
message: `${invalidVars.length} variable(s) may have invalid types`,
|
|
165
|
+
details: invalidVars.map(v => `${v.name} (expected: ${v.expectedType})`).join(', '),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
return results;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Generate a .env.missing report file
|
|
172
|
+
*/
|
|
173
|
+
export async function generateMissingEnvReport(cwd) {
|
|
174
|
+
const envExamplePath = path.join(cwd, '.env.example');
|
|
175
|
+
const envPath = path.join(cwd, '.env');
|
|
176
|
+
if (!await fs.pathExists(envExamplePath)) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
const exampleContent = await fs.readFile(envExamplePath, 'utf-8');
|
|
180
|
+
const exampleVars = parseEnvFile(exampleContent);
|
|
181
|
+
let envVars = {};
|
|
182
|
+
if (await fs.pathExists(envPath)) {
|
|
183
|
+
const envContent = await fs.readFile(envPath, 'utf-8');
|
|
184
|
+
envVars = parseEnvFile(envContent);
|
|
185
|
+
}
|
|
186
|
+
const missingVars = [];
|
|
187
|
+
for (const name of Object.keys(exampleVars)) {
|
|
188
|
+
if (envVars[name] === undefined || envVars[name] === '') {
|
|
189
|
+
missingVars.push(name);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (missingVars.length === 0) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
// Generate report content
|
|
196
|
+
const reportContent = `# Missing Environment Variables Report
|
|
197
|
+
# Generated: ${new Date().toISOString()}
|
|
198
|
+
#
|
|
199
|
+
# The following variables are defined in .env.example but missing from .env:
|
|
200
|
+
|
|
201
|
+
${missingVars.map(v => `${v}=`).join('\n')}
|
|
202
|
+
`;
|
|
203
|
+
const reportPath = path.join(cwd, '.env.missing');
|
|
204
|
+
await fs.writeFile(reportPath, reportContent, 'utf-8');
|
|
205
|
+
return reportPath;
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=check-env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-env.js","sourceRoot":"","sources":["../../../src/utils/doctor/check-env.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint and TypeScript compilation checks
|
|
3
|
+
*/
|
|
4
|
+
import { execSync } from 'child_process';
|
|
5
|
+
import fs from 'fs-extra';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
/**
|
|
8
|
+
* Check if ESLint is configured in the project
|
|
9
|
+
*/
|
|
10
|
+
async function hasEslintConfig(cwd) {
|
|
11
|
+
const eslintFiles = [
|
|
12
|
+
'.eslintrc',
|
|
13
|
+
'.eslintrc.js',
|
|
14
|
+
'.eslintrc.cjs',
|
|
15
|
+
'.eslintrc.json',
|
|
16
|
+
'.eslintrc.yml',
|
|
17
|
+
'.eslintrc.yaml',
|
|
18
|
+
'eslint.config.js',
|
|
19
|
+
'eslint.config.mjs',
|
|
20
|
+
'eslint.config.cjs',
|
|
21
|
+
];
|
|
22
|
+
for (const file of eslintFiles) {
|
|
23
|
+
if (await fs.pathExists(path.join(cwd, file))) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Check package.json for eslintConfig
|
|
28
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
29
|
+
if (await fs.pathExists(pkgPath)) {
|
|
30
|
+
try {
|
|
31
|
+
const pkg = await fs.readJson(pkgPath);
|
|
32
|
+
if (pkg.eslintConfig)
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Ignore JSON parse errors
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Check if TypeScript is configured in the project
|
|
43
|
+
*/
|
|
44
|
+
async function hasTypescriptConfig(cwd) {
|
|
45
|
+
return await fs.pathExists(path.join(cwd, 'tsconfig.json'));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Run ESLint and return results
|
|
49
|
+
*/
|
|
50
|
+
async function runEslint(cwd) {
|
|
51
|
+
if (!await hasEslintConfig(cwd)) {
|
|
52
|
+
return {
|
|
53
|
+
name: 'ESLint',
|
|
54
|
+
status: 'skip',
|
|
55
|
+
message: 'No ESLint configuration found',
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
// Check if ESLint is installed
|
|
60
|
+
const eslintPath = path.join(cwd, 'node_modules', '.bin', 'eslint');
|
|
61
|
+
if (!await fs.pathExists(eslintPath) && !await fs.pathExists(eslintPath + '.cmd')) {
|
|
62
|
+
return {
|
|
63
|
+
name: 'ESLint',
|
|
64
|
+
status: 'warn',
|
|
65
|
+
message: 'ESLint is not installed',
|
|
66
|
+
fix: 'Run: npm install eslint --save-dev',
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// Run ESLint with JSON output
|
|
70
|
+
const output = execSync('npx eslint . --format json --max-warnings 0', {
|
|
71
|
+
cwd,
|
|
72
|
+
encoding: 'utf-8',
|
|
73
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
74
|
+
timeout: 60000,
|
|
75
|
+
});
|
|
76
|
+
try {
|
|
77
|
+
const results = JSON.parse(output);
|
|
78
|
+
let errorCount = 0;
|
|
79
|
+
let warningCount = 0;
|
|
80
|
+
for (const file of results) {
|
|
81
|
+
errorCount += file.errorCount || 0;
|
|
82
|
+
warningCount += file.warningCount || 0;
|
|
83
|
+
}
|
|
84
|
+
if (errorCount > 0) {
|
|
85
|
+
return {
|
|
86
|
+
name: 'ESLint',
|
|
87
|
+
status: 'fail',
|
|
88
|
+
message: `${errorCount} error(s), ${warningCount} warning(s)`,
|
|
89
|
+
fix: 'Run: npx eslint . --fix',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (warningCount > 0) {
|
|
93
|
+
return {
|
|
94
|
+
name: 'ESLint',
|
|
95
|
+
status: 'warn',
|
|
96
|
+
message: `${warningCount} warning(s)`,
|
|
97
|
+
fix: 'Run: npx eslint . --fix',
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
name: 'ESLint',
|
|
102
|
+
status: 'pass',
|
|
103
|
+
message: 'No linting issues found',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// JSON parse failed, but command succeeded
|
|
108
|
+
return {
|
|
109
|
+
name: 'ESLint',
|
|
110
|
+
status: 'pass',
|
|
111
|
+
message: 'No linting issues found',
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
const errorOutput = error instanceof Error ? error.message : String(error);
|
|
117
|
+
// Try to parse error output as JSON
|
|
118
|
+
try {
|
|
119
|
+
const jsonMatch = errorOutput.match(/\[[\s\S]*\]/);
|
|
120
|
+
if (jsonMatch) {
|
|
121
|
+
const results = JSON.parse(jsonMatch[0]);
|
|
122
|
+
let errorCount = 0;
|
|
123
|
+
let warningCount = 0;
|
|
124
|
+
for (const file of results) {
|
|
125
|
+
errorCount += file.errorCount || 0;
|
|
126
|
+
warningCount += file.warningCount || 0;
|
|
127
|
+
}
|
|
128
|
+
if (errorCount > 0 || warningCount > 0) {
|
|
129
|
+
return {
|
|
130
|
+
name: 'ESLint',
|
|
131
|
+
status: errorCount > 0 ? 'fail' : 'warn',
|
|
132
|
+
message: `${errorCount} error(s), ${warningCount} warning(s)`,
|
|
133
|
+
fix: 'Run: npx eslint . --fix',
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// JSON parse failed
|
|
140
|
+
}
|
|
141
|
+
// Check for common error patterns
|
|
142
|
+
if (errorOutput.includes('error') || errorOutput.includes('Error')) {
|
|
143
|
+
return {
|
|
144
|
+
name: 'ESLint',
|
|
145
|
+
status: 'fail',
|
|
146
|
+
message: 'ESLint found issues',
|
|
147
|
+
details: errorOutput.substring(0, 200),
|
|
148
|
+
fix: 'Run: npx eslint . --fix',
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
name: 'ESLint',
|
|
153
|
+
status: 'fail',
|
|
154
|
+
message: 'ESLint check failed',
|
|
155
|
+
details: errorOutput.substring(0, 200),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Run TypeScript compiler check
|
|
161
|
+
*/
|
|
162
|
+
async function runTypecheck(cwd) {
|
|
163
|
+
if (!await hasTypescriptConfig(cwd)) {
|
|
164
|
+
return {
|
|
165
|
+
name: 'TypeScript',
|
|
166
|
+
status: 'skip',
|
|
167
|
+
message: 'No tsconfig.json found',
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
// Check if TypeScript is installed
|
|
172
|
+
const tscPath = path.join(cwd, 'node_modules', '.bin', 'tsc');
|
|
173
|
+
if (!await fs.pathExists(tscPath) && !await fs.pathExists(tscPath + '.cmd')) {
|
|
174
|
+
return {
|
|
175
|
+
name: 'TypeScript',
|
|
176
|
+
status: 'warn',
|
|
177
|
+
message: 'TypeScript is not installed',
|
|
178
|
+
fix: 'Run: npm install typescript --save-dev',
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
// Run tsc --noEmit
|
|
182
|
+
execSync('npx tsc --noEmit', {
|
|
183
|
+
cwd,
|
|
184
|
+
encoding: 'utf-8',
|
|
185
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
186
|
+
timeout: 120000,
|
|
187
|
+
});
|
|
188
|
+
return {
|
|
189
|
+
name: 'TypeScript',
|
|
190
|
+
status: 'pass',
|
|
191
|
+
message: 'No type errors found',
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
const errorOutput = error instanceof Error ? error.message : String(error);
|
|
196
|
+
// Count errors
|
|
197
|
+
const errorMatches = errorOutput.match(/error TS\d+/g);
|
|
198
|
+
const errorCount = errorMatches ? errorMatches.length : 0;
|
|
199
|
+
if (errorCount > 0) {
|
|
200
|
+
return {
|
|
201
|
+
name: 'TypeScript',
|
|
202
|
+
status: 'fail',
|
|
203
|
+
message: `${errorCount} type error(s) found`,
|
|
204
|
+
details: errorOutput.split('\n').slice(0, 5).join('\n'),
|
|
205
|
+
fix: 'Fix the type errors in your TypeScript files',
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
name: 'TypeScript',
|
|
210
|
+
status: 'fail',
|
|
211
|
+
message: 'TypeScript compilation failed',
|
|
212
|
+
details: errorOutput.substring(0, 200),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Run all lint checks
|
|
218
|
+
*/
|
|
219
|
+
export async function runLintChecks(cwd) {
|
|
220
|
+
const results = [];
|
|
221
|
+
results.push(await runEslint(cwd));
|
|
222
|
+
results.push(await runTypecheck(cwd));
|
|
223
|
+
return results;
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=check-lint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-lint.js","sourceRoot":"","sources":["../../../src/utils/doctor/check-lint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js and package manager version checks
|
|
3
|
+
*/
|
|
4
|
+
import type { CheckResult } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Check Node.js version
|
|
7
|
+
*/
|
|
8
|
+
export declare function checkNodeVersion(cwd: string): Promise<CheckResult>;
|
|
9
|
+
/**
|
|
10
|
+
* Check npm version
|
|
11
|
+
*/
|
|
12
|
+
export declare function checkNpmVersion(): Promise<CheckResult>;
|
|
13
|
+
/**
|
|
14
|
+
* Check pnpm installation (optional)
|
|
15
|
+
*/
|
|
16
|
+
export declare function checkPnpmVersion(): Promise<CheckResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Run all Node/package manager checks
|
|
19
|
+
*/
|
|
20
|
+
export declare function runNodeChecks(cwd: string): Promise<CheckResult[]>;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js and package manager version checks
|
|
3
|
+
*/
|
|
4
|
+
import { execSync } from 'child_process';
|
|
5
|
+
import fs from 'fs-extra';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
/**
|
|
8
|
+
* Parse semantic version string
|
|
9
|
+
*/
|
|
10
|
+
function parseVersion(version) {
|
|
11
|
+
const match = version.match(/(\d+)\.(\d+)\.(\d+)/);
|
|
12
|
+
if (!match)
|
|
13
|
+
return null;
|
|
14
|
+
return {
|
|
15
|
+
major: parseInt(match[1], 10),
|
|
16
|
+
minor: parseInt(match[2], 10),
|
|
17
|
+
patch: parseInt(match[3], 10),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Compare two versions, returns: -1 if a < b, 0 if equal, 1 if a > b
|
|
22
|
+
*/
|
|
23
|
+
function compareVersions(a, b) {
|
|
24
|
+
const va = parseVersion(a);
|
|
25
|
+
const vb = parseVersion(b);
|
|
26
|
+
if (!va || !vb)
|
|
27
|
+
return 0;
|
|
28
|
+
if (va.major !== vb.major)
|
|
29
|
+
return va.major - vb.major;
|
|
30
|
+
if (va.minor !== vb.minor)
|
|
31
|
+
return va.minor - vb.minor;
|
|
32
|
+
return va.patch - vb.patch;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get the required Node version from project config
|
|
36
|
+
*/
|
|
37
|
+
async function getRequiredNodeVersion(cwd) {
|
|
38
|
+
// Check .nvmrc first
|
|
39
|
+
const nvmrcPath = path.join(cwd, '.nvmrc');
|
|
40
|
+
if (await fs.pathExists(nvmrcPath)) {
|
|
41
|
+
const content = await fs.readFile(nvmrcPath, 'utf-8');
|
|
42
|
+
return content.trim().replace(/^v/, '');
|
|
43
|
+
}
|
|
44
|
+
// Check package.json engines
|
|
45
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
46
|
+
if (await fs.pathExists(pkgPath)) {
|
|
47
|
+
try {
|
|
48
|
+
const pkg = await fs.readJson(pkgPath);
|
|
49
|
+
if (pkg.engines?.node) {
|
|
50
|
+
// Parse engine string like ">=18" or "^20.0.0"
|
|
51
|
+
const match = pkg.engines.node.match(/\d+(\.\d+)?(\.\d+)?/);
|
|
52
|
+
return match ? match[0] : null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Ignore JSON parse errors
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Execute command and return output, or null on failure
|
|
63
|
+
*/
|
|
64
|
+
function execCommand(command) {
|
|
65
|
+
try {
|
|
66
|
+
return execSync(command, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Check Node.js version
|
|
74
|
+
*/
|
|
75
|
+
export async function checkNodeVersion(cwd) {
|
|
76
|
+
const nodeVersion = execCommand('node --version');
|
|
77
|
+
if (!nodeVersion) {
|
|
78
|
+
return {
|
|
79
|
+
name: 'Node.js',
|
|
80
|
+
status: 'fail',
|
|
81
|
+
message: 'Node.js is not installed',
|
|
82
|
+
fix: 'Install Node.js from https://nodejs.org/',
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const version = nodeVersion.replace(/^v/, '');
|
|
86
|
+
const requiredVersion = await getRequiredNodeVersion(cwd);
|
|
87
|
+
if (requiredVersion) {
|
|
88
|
+
const comparison = compareVersions(version, requiredVersion);
|
|
89
|
+
if (comparison < 0) {
|
|
90
|
+
return {
|
|
91
|
+
name: 'Node.js',
|
|
92
|
+
status: 'fail',
|
|
93
|
+
message: `Node version ${version} is below required ${requiredVersion}`,
|
|
94
|
+
fix: `Update Node.js to version ${requiredVersion} or higher`,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Minimum supported version is 18
|
|
99
|
+
const parsed = parseVersion(version);
|
|
100
|
+
if (parsed && parsed.major < 18) {
|
|
101
|
+
return {
|
|
102
|
+
name: 'Node.js',
|
|
103
|
+
status: 'fail',
|
|
104
|
+
message: `Node version ${version} is too old (minimum: 18.x)`,
|
|
105
|
+
fix: 'Update Node.js to version 18 or higher',
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
name: 'Node.js',
|
|
110
|
+
status: 'pass',
|
|
111
|
+
message: `Node version: ${version}`,
|
|
112
|
+
details: requiredVersion ? `Required: >=${requiredVersion}` : undefined,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Check npm version
|
|
117
|
+
*/
|
|
118
|
+
export async function checkNpmVersion() {
|
|
119
|
+
const npmVersion = execCommand('npm --version');
|
|
120
|
+
if (!npmVersion) {
|
|
121
|
+
return {
|
|
122
|
+
name: 'npm',
|
|
123
|
+
status: 'fail',
|
|
124
|
+
message: 'npm is not installed',
|
|
125
|
+
fix: 'npm should be installed with Node.js. Try reinstalling Node.js.',
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const parsed = parseVersion(npmVersion);
|
|
129
|
+
if (parsed && parsed.major < 8) {
|
|
130
|
+
return {
|
|
131
|
+
name: 'npm',
|
|
132
|
+
status: 'warn',
|
|
133
|
+
message: `npm version ${npmVersion} is outdated`,
|
|
134
|
+
fix: 'Run: npm install -g npm@latest',
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
name: 'npm',
|
|
139
|
+
status: 'pass',
|
|
140
|
+
message: `npm version: ${npmVersion}`,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Check pnpm installation (optional)
|
|
145
|
+
*/
|
|
146
|
+
export async function checkPnpmVersion() {
|
|
147
|
+
const pnpmVersion = execCommand('pnpm --version');
|
|
148
|
+
if (!pnpmVersion) {
|
|
149
|
+
return {
|
|
150
|
+
name: 'pnpm',
|
|
151
|
+
status: 'skip',
|
|
152
|
+
message: 'pnpm is not installed (optional)',
|
|
153
|
+
details: 'pnpm is an alternative package manager',
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
name: 'pnpm',
|
|
158
|
+
status: 'pass',
|
|
159
|
+
message: `pnpm version: ${pnpmVersion}`,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Run all Node/package manager checks
|
|
164
|
+
*/
|
|
165
|
+
export async function runNodeChecks(cwd) {
|
|
166
|
+
const results = [];
|
|
167
|
+
results.push(await checkNodeVersion(cwd));
|
|
168
|
+
results.push(await checkNpmVersion());
|
|
169
|
+
results.push(await checkPnpmVersion());
|
|
170
|
+
return results;
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=check-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-node.js","sourceRoot":"","sources":["../../../src/utils/doctor/check-node.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB;;GAEG;AACH,SAAS,YAAY,CAAC,OAAe;IACjC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACnD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO;QACH,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QAC7B,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QAC7B,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;KAChC,CAAC;AACN,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,CAAS,EAAE,CAAS;IACzC,MAAM,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,CAAC;IAEzB,IAAI,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC;IACtD,IAAI,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC;IACtD,OAAO,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,sBAAsB,CAAC,GAAW;IAC7C,qBAAqB;IACrB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC3C,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACtD,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,6BAA6B;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAC/C,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,IAAI,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;gBACpB,+CAA+C;gBAC/C,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;gBAC5D,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YACnC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACL,2BAA2B;QAC/B,CAAC;IACL,CAAC;IAED,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,OAAe;IAChC,IAAI,CAAC;QACD,OAAO,QAAQ,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5F,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAW;IAC9C,MAAM,WAAW,GAAG,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAElD,IAAI,CAAC,WAAW,EAAE,CAAC;QACf,OAAO;YACH,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,0BAA0B;YACnC,GAAG,EAAE,0CAA0C;SAClD,CAAC;IACN,CAAC;IAED,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC9C,MAAM,eAAe,GAAG,MAAM,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAE1D,IAAI,eAAe,EAAE,CAAC;QAClB,MAAM,UAAU,GAAG,eAAe,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QAC7D,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACjB,OAAO;gBACH,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,gBAAgB,OAAO,sBAAsB,eAAe,EAAE;gBACvE,GAAG,EAAE,6BAA6B,eAAe,YAAY;aAChE,CAAC;QACN,CAAC;IACL,CAAC;IAED,kCAAkC;IAClC,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACrC,IAAI,MAAM,IAAI,MAAM,CAAC,KAAK,GAAG,EAAE,EAAE,CAAC;QAC9B,OAAO;YACH,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,gBAAgB,OAAO,6BAA6B;YAC7D,GAAG,EAAE,wCAAwC;SAChD,CAAC;IACN,CAAC;IAED,OAAO;QACH,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,iBAAiB,OAAO,EAAE;QACnC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,eAAe,eAAe,EAAE,CAAC,CAAC,CAAC,SAAS;KAC1E,CAAC;AACN,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACjC,MAAM,UAAU,GAAG,WAAW,CAAC,eAAe,CAAC,CAAC;IAEhD,IAAI,CAAC,UAAU,EAAE,CAAC;QACd,OAAO;YACH,IAAI,EAAE,KAAK;YACX,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,sBAAsB;YAC/B,GAAG,EAAE,iEAAiE;SACzE,CAAC;IACN,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IACxC,IAAI,MAAM,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO;YACH,IAAI,EAAE,KAAK;YACX,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,eAAe,UAAU,cAAc;YAChD,GAAG,EAAE,gCAAgC;SACxC,CAAC;IACN,CAAC;IAED,OAAO;QACH,IAAI,EAAE,KAAK;QACX,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,gBAAgB,UAAU,EAAE;KACxC,CAAC;AACN,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IAClC,MAAM,WAAW,GAAG,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAElD,IAAI,CAAC,WAAW,EAAE,CAAC;QACf,OAAO;YACH,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,kCAAkC;YAC3C,OAAO,EAAE,wCAAwC;SACpD,CAAC;IACN,CAAC;IAED,OAAO;QACH,IAAI,EAAE,MAAM;QACZ,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,iBAAiB,WAAW,EAAE;KAC1C,CAAC;AACN,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW;IAC3C,MAAM,OAAO,GAAkB,EAAE,CAAC;IAElC,OAAO,CAAC,IAAI,CAAC,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1C,OAAO,CAAC,IAAI,CAAC,MAAM,eAAe,EAAE,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,MAAM,gBAAgB,EAAE,CAAC,CAAC;IAEvC,OAAO,OAAO,CAAC;AACnB,CAAC"}
|