mycontext-cli 2.0.2 â 2.0.3
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/dist/agents/implementations/CodeGenSubAgent.d.ts.map +1 -1
- package/dist/agents/implementations/CodeGenSubAgent.js +69 -0
- package/dist/agents/implementations/CodeGenSubAgent.js.map +1 -1
- package/dist/agents/implementations/PromptConstructorAgent.d.ts.map +1 -1
- package/dist/agents/implementations/PromptConstructorAgent.js +23 -0
- package/dist/agents/implementations/PromptConstructorAgent.js.map +1 -1
- package/dist/cli.js +11 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/health-check.d.ts +28 -0
- package/dist/commands/health-check.d.ts.map +1 -0
- package/dist/commands/health-check.js +271 -0
- package/dist/commands/health-check.js.map +1 -0
- package/dist/package.json +1 -1
- package/dist/utils/NextJSProjectGenerator.d.ts +70 -0
- package/dist/utils/NextJSProjectGenerator.d.ts.map +1 -0
- package/dist/utils/NextJSProjectGenerator.js +811 -0
- package/dist/utils/NextJSProjectGenerator.js.map +1 -0
- package/dist/utils/NextJSProjectValidator.d.ts +103 -0
- package/dist/utils/NextJSProjectValidator.d.ts.map +1 -0
- package/dist/utils/NextJSProjectValidator.js +759 -0
- package/dist/utils/NextJSProjectValidator.js.map +1 -0
- package/dist/utils/PreCommandValidator.d.ts +77 -0
- package/dist/utils/PreCommandValidator.d.ts.map +1 -0
- package/dist/utils/PreCommandValidator.js +251 -0
- package/dist/utils/PreCommandValidator.js.map +1 -0
- package/dist/utils/ProjectHealthMonitor.d.ts +131 -0
- package/dist/utils/ProjectHealthMonitor.d.ts.map +1 -0
- package/dist/utils/ProjectHealthMonitor.js +454 -0
- package/dist/utils/ProjectHealthMonitor.js.map +1 -0
- package/dist/utils/ProjectInitializationSafeguards.d.ts +81 -0
- package/dist/utils/ProjectInitializationSafeguards.d.ts.map +1 -0
- package/dist/utils/ProjectInitializationSafeguards.js +620 -0
- package/dist/utils/ProjectInitializationSafeguards.js.map +1 -0
- package/dist/utils/ProjectStructureRepair.d.ts +110 -0
- package/dist/utils/ProjectStructureRepair.d.ts.map +1 -0
- package/dist/utils/ProjectStructureRepair.js +785 -0
- package/dist/utils/ProjectStructureRepair.js.map +1 -0
- package/dist/utils/ProjectStructureValidator.d.ts +128 -0
- package/dist/utils/ProjectStructureValidator.d.ts.map +1 -0
- package/dist/utils/ProjectStructureValidator.js +662 -0
- package/dist/utils/ProjectStructureValidator.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,662 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.ProjectStructureValidator = void 0;
|
|
40
|
+
const fs = __importStar(require("fs-extra"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
43
|
+
const NextJSProjectValidator_1 = require("./NextJSProjectValidator");
|
|
44
|
+
class ProjectStructureValidator {
|
|
45
|
+
constructor(projectRoot = process.cwd()) {
|
|
46
|
+
this.issues = [];
|
|
47
|
+
this.projectRoot = projectRoot;
|
|
48
|
+
this.metrics = this.calculateMetrics();
|
|
49
|
+
this.nextjsValidator = new NextJSProjectValidator_1.NextJSProjectValidator(projectRoot);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Comprehensive project structure validation
|
|
53
|
+
*/
|
|
54
|
+
async validate() {
|
|
55
|
+
this.issues = [];
|
|
56
|
+
console.log(chalk_1.default.blue("đ Validating project structure..."));
|
|
57
|
+
// Run all validation checks
|
|
58
|
+
await this.checkPackageJsonFiles();
|
|
59
|
+
await this.checkNodeModulesDirectories();
|
|
60
|
+
await this.checkLockFiles();
|
|
61
|
+
await this.checkTypeScriptConfigs();
|
|
62
|
+
await this.checkBuildConfigs();
|
|
63
|
+
await this.checkProjectDepth();
|
|
64
|
+
await this.checkPathIssues();
|
|
65
|
+
await this.checkDependencyConflicts();
|
|
66
|
+
// Run Next.js specific validation
|
|
67
|
+
const nextjsReport = await this.nextjsValidator.validateNextJSProject();
|
|
68
|
+
this.issues.push(...nextjsReport.issues.map((issue) => ({
|
|
69
|
+
type: issue.type,
|
|
70
|
+
severity: issue.severity,
|
|
71
|
+
message: issue.message,
|
|
72
|
+
file: issue.file,
|
|
73
|
+
fix: issue.fix,
|
|
74
|
+
autoFixable: issue.autoFixable,
|
|
75
|
+
})));
|
|
76
|
+
const isValid = this.issues.filter((issue) => issue.type === "error").length === 0;
|
|
77
|
+
const autoFixable = this.issues.every((issue) => issue.autoFixable);
|
|
78
|
+
return {
|
|
79
|
+
isValid,
|
|
80
|
+
issues: this.issues,
|
|
81
|
+
metrics: this.metrics,
|
|
82
|
+
recommendations: this.generateRecommendations(),
|
|
83
|
+
autoFixable,
|
|
84
|
+
nextjsCompliant: nextjsReport.appRouterCompliant,
|
|
85
|
+
shadcnCompliant: nextjsReport.shadcnCompliant,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Check for multiple package.json files
|
|
90
|
+
*/
|
|
91
|
+
async checkPackageJsonFiles() {
|
|
92
|
+
const packageJsonFiles = await this.findFiles("package.json");
|
|
93
|
+
if (packageJsonFiles.length === 0) {
|
|
94
|
+
this.addIssue({
|
|
95
|
+
type: "error",
|
|
96
|
+
severity: "critical",
|
|
97
|
+
message: "No package.json file found in project root",
|
|
98
|
+
autoFixable: false,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
else if (packageJsonFiles.length > 1) {
|
|
102
|
+
this.addIssue({
|
|
103
|
+
type: "error",
|
|
104
|
+
severity: "critical",
|
|
105
|
+
message: `Multiple package.json files detected (${packageJsonFiles.length} found)`,
|
|
106
|
+
file: packageJsonFiles.join(", "),
|
|
107
|
+
fix: "Remove nested package.json files and consolidate dependencies",
|
|
108
|
+
autoFixable: true,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Check for nested node_modules directories
|
|
114
|
+
*/
|
|
115
|
+
async checkNodeModulesDirectories() {
|
|
116
|
+
const nodeModulesDirs = await this.findDirectories("node_modules");
|
|
117
|
+
if (nodeModulesDirs.length === 0) {
|
|
118
|
+
this.addIssue({
|
|
119
|
+
type: "warning",
|
|
120
|
+
severity: "medium",
|
|
121
|
+
message: "No node_modules directory found. Run 'pnpm install' to install dependencies",
|
|
122
|
+
autoFixable: true,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
else if (nodeModulesDirs.length > 1) {
|
|
126
|
+
this.addIssue({
|
|
127
|
+
type: "error",
|
|
128
|
+
severity: "critical",
|
|
129
|
+
message: `Nested node_modules directories detected (${nodeModulesDirs.length} found)`,
|
|
130
|
+
file: nodeModulesDirs.join(", "),
|
|
131
|
+
fix: "Remove nested node_modules directories and reinstall dependencies",
|
|
132
|
+
autoFixable: true,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Check for multiple lock files
|
|
138
|
+
*/
|
|
139
|
+
async checkLockFiles() {
|
|
140
|
+
const lockFiles = await this.findFiles("*-lock.yaml", "package-lock.json", "yarn.lock", "bun.lockb");
|
|
141
|
+
if (lockFiles.length === 0) {
|
|
142
|
+
this.addIssue({
|
|
143
|
+
type: "warning",
|
|
144
|
+
severity: "medium",
|
|
145
|
+
message: "No lock file found. Run 'pnpm install' to generate pnpm-lock.yaml",
|
|
146
|
+
autoFixable: true,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
else if (lockFiles.length > 1) {
|
|
150
|
+
this.addIssue({
|
|
151
|
+
type: "error",
|
|
152
|
+
severity: "critical",
|
|
153
|
+
message: `Multiple lock files detected (${lockFiles.length} found)`,
|
|
154
|
+
file: lockFiles.join(", "),
|
|
155
|
+
fix: "Remove conflicting lock files and keep only pnpm-lock.yaml",
|
|
156
|
+
autoFixable: true,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Check for multiple TypeScript configurations
|
|
162
|
+
*/
|
|
163
|
+
async checkTypeScriptConfigs() {
|
|
164
|
+
const tsConfigFiles = await this.findFiles("tsconfig*.json");
|
|
165
|
+
if (tsConfigFiles.length === 0) {
|
|
166
|
+
this.addIssue({
|
|
167
|
+
type: "error",
|
|
168
|
+
severity: "high",
|
|
169
|
+
message: "No TypeScript configuration found",
|
|
170
|
+
autoFixable: true,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
else if (tsConfigFiles.length > 2) {
|
|
174
|
+
this.addIssue({
|
|
175
|
+
type: "warning",
|
|
176
|
+
severity: "medium",
|
|
177
|
+
message: `Multiple TypeScript configurations detected (${tsConfigFiles.length} found)`,
|
|
178
|
+
file: tsConfigFiles.join(", "),
|
|
179
|
+
fix: "Consider consolidating TypeScript configurations",
|
|
180
|
+
autoFixable: false,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Check for multiple build configurations
|
|
186
|
+
*/
|
|
187
|
+
async checkBuildConfigs() {
|
|
188
|
+
const buildConfigs = await this.findFiles("next.config.*", "webpack.config.*", "vite.config.*", "rollup.config.*", "esbuild.config.*");
|
|
189
|
+
if (buildConfigs.length === 0) {
|
|
190
|
+
this.addIssue({
|
|
191
|
+
type: "warning",
|
|
192
|
+
severity: "medium",
|
|
193
|
+
message: "No build configuration found",
|
|
194
|
+
autoFixable: true,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
else if (buildConfigs.length > 1) {
|
|
198
|
+
this.addIssue({
|
|
199
|
+
type: "error",
|
|
200
|
+
severity: "high",
|
|
201
|
+
message: `Multiple build configurations detected (${buildConfigs.length} found)`,
|
|
202
|
+
file: buildConfigs.join(", "),
|
|
203
|
+
fix: "Remove conflicting build configurations and keep only Next.js config",
|
|
204
|
+
autoFixable: true,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Check project depth and path issues
|
|
210
|
+
*/
|
|
211
|
+
async checkProjectDepth() {
|
|
212
|
+
const depth = this.calculateProjectDepth();
|
|
213
|
+
if (depth > 6) {
|
|
214
|
+
this.addIssue({
|
|
215
|
+
type: "warning",
|
|
216
|
+
severity: "medium",
|
|
217
|
+
message: `Project path is deeply nested (${depth} levels). Consider moving to a shorter path`,
|
|
218
|
+
autoFixable: false,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
if (this.projectRoot.includes(" ")) {
|
|
222
|
+
this.addIssue({
|
|
223
|
+
type: "warning",
|
|
224
|
+
severity: "medium",
|
|
225
|
+
message: "Project path contains spaces, which may cause issues with some tools",
|
|
226
|
+
autoFixable: false,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Check for dependency conflicts
|
|
232
|
+
*/
|
|
233
|
+
async checkDependencyConflicts() {
|
|
234
|
+
try {
|
|
235
|
+
const packageJsonPath = path.join(this.projectRoot, "package.json");
|
|
236
|
+
if (await fs.pathExists(packageJsonPath)) {
|
|
237
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
238
|
+
// Check for package manager conflicts
|
|
239
|
+
if (packageJson.packageManager &&
|
|
240
|
+
!packageJson.packageManager.includes("pnpm")) {
|
|
241
|
+
this.addIssue({
|
|
242
|
+
type: "warning",
|
|
243
|
+
severity: "medium",
|
|
244
|
+
message: "Package manager specified is not pnpm",
|
|
245
|
+
fix: "Update packageManager field to use pnpm",
|
|
246
|
+
autoFixable: true,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
// Check for duplicate dependencies
|
|
250
|
+
const allDeps = {
|
|
251
|
+
...(packageJson.dependencies || {}),
|
|
252
|
+
...(packageJson.devDependencies || {}),
|
|
253
|
+
...(packageJson.peerDependencies || {}),
|
|
254
|
+
};
|
|
255
|
+
const duplicateDeps = this.findDuplicateDependencies(allDeps);
|
|
256
|
+
if (duplicateDeps.length > 0) {
|
|
257
|
+
this.addIssue({
|
|
258
|
+
type: "warning",
|
|
259
|
+
severity: "low",
|
|
260
|
+
message: `Potential duplicate dependencies: ${duplicateDeps.join(", ")}`,
|
|
261
|
+
autoFixable: false,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
this.addIssue({
|
|
268
|
+
type: "error",
|
|
269
|
+
severity: "medium",
|
|
270
|
+
message: `Failed to read package.json: ${error}`,
|
|
271
|
+
autoFixable: false,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Check for path-related issues
|
|
277
|
+
*/
|
|
278
|
+
async checkPathIssues() {
|
|
279
|
+
const pathIssues = [];
|
|
280
|
+
// Check for special characters in path
|
|
281
|
+
if (/[<>:"|?*]/.test(this.projectRoot)) {
|
|
282
|
+
pathIssues.push("contains invalid characters");
|
|
283
|
+
}
|
|
284
|
+
// Check for very long paths
|
|
285
|
+
if (this.projectRoot.length > 200) {
|
|
286
|
+
pathIssues.push("path is very long");
|
|
287
|
+
}
|
|
288
|
+
if (pathIssues.length > 0) {
|
|
289
|
+
this.addIssue({
|
|
290
|
+
type: "warning",
|
|
291
|
+
severity: "low",
|
|
292
|
+
message: `Project path ${pathIssues.join(" and ")}`,
|
|
293
|
+
autoFixable: false,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Auto-fix detected issues
|
|
299
|
+
*/
|
|
300
|
+
async autoFix() {
|
|
301
|
+
const report = await this.validate();
|
|
302
|
+
let fixed = 0;
|
|
303
|
+
let failed = 0;
|
|
304
|
+
const errors = [];
|
|
305
|
+
console.log(chalk_1.default.blue("đ§ Attempting to auto-fix issues..."));
|
|
306
|
+
for (const issue of report.issues) {
|
|
307
|
+
if (issue.autoFixable) {
|
|
308
|
+
try {
|
|
309
|
+
await this.fixIssue(issue);
|
|
310
|
+
fixed++;
|
|
311
|
+
console.log(chalk_1.default.green(`â
Fixed: ${issue.message}`));
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
failed++;
|
|
315
|
+
errors.push(`Failed to fix "${issue.message}": ${error}`);
|
|
316
|
+
console.log(chalk_1.default.red(`â Failed to fix: ${issue.message}`));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return { fixed, failed, errors };
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Fix a specific issue
|
|
324
|
+
*/
|
|
325
|
+
async fixIssue(issue) {
|
|
326
|
+
switch (issue.type) {
|
|
327
|
+
case "error":
|
|
328
|
+
if (issue.message.includes("Multiple package.json")) {
|
|
329
|
+
await this.removeNestedPackageJson();
|
|
330
|
+
}
|
|
331
|
+
else if (issue.message.includes("Nested node_modules")) {
|
|
332
|
+
await this.removeNestedNodeModules();
|
|
333
|
+
}
|
|
334
|
+
else if (issue.message.includes("Multiple lock files")) {
|
|
335
|
+
await this.removeConflictingLockFiles();
|
|
336
|
+
}
|
|
337
|
+
else if (issue.message.includes("Multiple build configurations")) {
|
|
338
|
+
await this.removeConflictingBuildConfigs();
|
|
339
|
+
}
|
|
340
|
+
break;
|
|
341
|
+
case "warning":
|
|
342
|
+
if (issue.message.includes("No package.json")) {
|
|
343
|
+
await this.createDefaultPackageJson();
|
|
344
|
+
}
|
|
345
|
+
else if (issue.message.includes("No lock file")) {
|
|
346
|
+
await this.generateLockFile();
|
|
347
|
+
}
|
|
348
|
+
else if (issue.message.includes("No TypeScript configuration")) {
|
|
349
|
+
await this.createDefaultTsConfig();
|
|
350
|
+
}
|
|
351
|
+
else if (issue.message.includes("No build configuration")) {
|
|
352
|
+
await this.createDefaultNextConfig();
|
|
353
|
+
}
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Remove nested package.json files
|
|
359
|
+
*/
|
|
360
|
+
async removeNestedPackageJson() {
|
|
361
|
+
const packageJsonFiles = await this.findFiles("package.json");
|
|
362
|
+
const rootPackageJson = path.join(this.projectRoot, "package.json");
|
|
363
|
+
for (const file of packageJsonFiles) {
|
|
364
|
+
if (file !== rootPackageJson) {
|
|
365
|
+
await fs.remove(file);
|
|
366
|
+
console.log(chalk_1.default.yellow(`đī¸ Removed nested package.json: ${file}`));
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Remove nested node_modules directories
|
|
372
|
+
*/
|
|
373
|
+
async removeNestedNodeModules() {
|
|
374
|
+
const nodeModulesDirs = await this.findDirectories("node_modules");
|
|
375
|
+
const rootNodeModules = path.join(this.projectRoot, "node_modules");
|
|
376
|
+
for (const dir of nodeModulesDirs) {
|
|
377
|
+
if (dir !== rootNodeModules) {
|
|
378
|
+
await fs.remove(dir);
|
|
379
|
+
console.log(chalk_1.default.yellow(`đī¸ Removed nested node_modules: ${dir}`));
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Remove conflicting lock files
|
|
385
|
+
*/
|
|
386
|
+
async removeConflictingLockFiles() {
|
|
387
|
+
const lockFiles = await this.findFiles("*-lock.yaml", "package-lock.json", "yarn.lock", "bun.lockb");
|
|
388
|
+
const preferredLockFile = path.join(this.projectRoot, "pnpm-lock.yaml");
|
|
389
|
+
for (const file of lockFiles) {
|
|
390
|
+
if (file !== preferredLockFile) {
|
|
391
|
+
await fs.remove(file);
|
|
392
|
+
console.log(chalk_1.default.yellow(`đī¸ Removed conflicting lock file: ${file}`));
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Remove conflicting build configurations
|
|
398
|
+
*/
|
|
399
|
+
async removeConflictingBuildConfigs() {
|
|
400
|
+
const buildConfigs = await this.findFiles("next.config.*", "webpack.config.*", "vite.config.*", "rollup.config.*", "esbuild.config.*");
|
|
401
|
+
const preferredConfig = path.join(this.projectRoot, "next.config.ts");
|
|
402
|
+
for (const file of buildConfigs) {
|
|
403
|
+
if (file !== preferredConfig) {
|
|
404
|
+
await fs.remove(file);
|
|
405
|
+
console.log(chalk_1.default.yellow(`đī¸ Removed conflicting build config: ${file}`));
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Create default package.json
|
|
411
|
+
*/
|
|
412
|
+
async createDefaultPackageJson() {
|
|
413
|
+
const defaultPackageJson = {
|
|
414
|
+
name: path.basename(this.projectRoot),
|
|
415
|
+
version: "0.1.0",
|
|
416
|
+
private: true,
|
|
417
|
+
scripts: {
|
|
418
|
+
dev: "next dev",
|
|
419
|
+
build: "next build",
|
|
420
|
+
start: "next start",
|
|
421
|
+
lint: "next lint",
|
|
422
|
+
},
|
|
423
|
+
dependencies: {
|
|
424
|
+
react: "^18.0.0",
|
|
425
|
+
"react-dom": "^18.0.0",
|
|
426
|
+
next: "^14.0.0",
|
|
427
|
+
},
|
|
428
|
+
devDependencies: {
|
|
429
|
+
typescript: "^5.0.0",
|
|
430
|
+
"@types/node": "^20.0.0",
|
|
431
|
+
"@types/react": "^18.0.0",
|
|
432
|
+
"@types/react-dom": "^18.0.0",
|
|
433
|
+
tailwindcss: "^3.0.0",
|
|
434
|
+
autoprefixer: "^10.0.0",
|
|
435
|
+
postcss: "^8.0.0",
|
|
436
|
+
},
|
|
437
|
+
packageManager: "pnpm@10.11.0",
|
|
438
|
+
};
|
|
439
|
+
await fs.writeJson(path.join(this.projectRoot, "package.json"), defaultPackageJson, { spaces: 2 });
|
|
440
|
+
console.log(chalk_1.default.green("â
Created default package.json"));
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Generate lock file
|
|
444
|
+
*/
|
|
445
|
+
async generateLockFile() {
|
|
446
|
+
const { execSync } = require("child_process");
|
|
447
|
+
try {
|
|
448
|
+
execSync("pnpm install", { cwd: this.projectRoot, stdio: "pipe" });
|
|
449
|
+
console.log(chalk_1.default.green("â
Generated pnpm-lock.yaml"));
|
|
450
|
+
}
|
|
451
|
+
catch (error) {
|
|
452
|
+
throw new Error("Failed to generate lock file");
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Create default TypeScript configuration
|
|
457
|
+
*/
|
|
458
|
+
async createDefaultTsConfig() {
|
|
459
|
+
const defaultTsConfig = {
|
|
460
|
+
compilerOptions: {
|
|
461
|
+
target: "es5",
|
|
462
|
+
lib: ["dom", "dom.iterable", "es6"],
|
|
463
|
+
allowJs: true,
|
|
464
|
+
skipLibCheck: true,
|
|
465
|
+
strict: true,
|
|
466
|
+
noEmit: true,
|
|
467
|
+
esModuleInterop: true,
|
|
468
|
+
module: "esnext",
|
|
469
|
+
moduleResolution: "bundler",
|
|
470
|
+
resolveJsonModule: true,
|
|
471
|
+
isolatedModules: true,
|
|
472
|
+
jsx: "preserve",
|
|
473
|
+
incremental: true,
|
|
474
|
+
plugins: [
|
|
475
|
+
{
|
|
476
|
+
name: "next",
|
|
477
|
+
},
|
|
478
|
+
],
|
|
479
|
+
paths: {
|
|
480
|
+
"@/*": ["./*"],
|
|
481
|
+
},
|
|
482
|
+
},
|
|
483
|
+
include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
484
|
+
exclude: ["node_modules"],
|
|
485
|
+
};
|
|
486
|
+
await fs.writeJson(path.join(this.projectRoot, "tsconfig.json"), defaultTsConfig, { spaces: 2 });
|
|
487
|
+
console.log(chalk_1.default.green("â
Created default tsconfig.json"));
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Create default Next.js configuration
|
|
491
|
+
*/
|
|
492
|
+
async createDefaultNextConfig() {
|
|
493
|
+
const defaultNextConfig = `import type { NextConfig } from "next";
|
|
494
|
+
|
|
495
|
+
const nextConfig: NextConfig = {
|
|
496
|
+
experimental: {
|
|
497
|
+
turbo: true,
|
|
498
|
+
},
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
export default nextConfig;
|
|
502
|
+
`;
|
|
503
|
+
await fs.writeFile(path.join(this.projectRoot, "next.config.ts"), defaultNextConfig);
|
|
504
|
+
console.log(chalk_1.default.green("â
Created default next.config.ts"));
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Helper methods
|
|
508
|
+
*/
|
|
509
|
+
async findFiles(...patterns) {
|
|
510
|
+
const files = [];
|
|
511
|
+
for (const pattern of patterns) {
|
|
512
|
+
const glob = require("glob");
|
|
513
|
+
const matches = await glob(pattern, {
|
|
514
|
+
cwd: this.projectRoot,
|
|
515
|
+
absolute: true,
|
|
516
|
+
ignore: ["**/node_modules/**"],
|
|
517
|
+
});
|
|
518
|
+
files.push(...matches);
|
|
519
|
+
}
|
|
520
|
+
return [...new Set(files)];
|
|
521
|
+
}
|
|
522
|
+
async findDirectories(dirName) {
|
|
523
|
+
const glob = require("glob");
|
|
524
|
+
const matches = await glob(`**/${dirName}`, {
|
|
525
|
+
cwd: this.projectRoot,
|
|
526
|
+
absolute: true,
|
|
527
|
+
ignore: ["**/node_modules/**"],
|
|
528
|
+
});
|
|
529
|
+
return matches;
|
|
530
|
+
}
|
|
531
|
+
calculateMetrics() {
|
|
532
|
+
return {
|
|
533
|
+
packageJsonCount: 0,
|
|
534
|
+
nodeModulesCount: 0,
|
|
535
|
+
lockFileCount: 0,
|
|
536
|
+
tsConfigCount: 0,
|
|
537
|
+
buildConfigCount: 0,
|
|
538
|
+
totalFiles: 0,
|
|
539
|
+
projectDepth: this.calculateProjectDepth(),
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
calculateProjectDepth() {
|
|
543
|
+
return this.projectRoot.split(path.sep).length;
|
|
544
|
+
}
|
|
545
|
+
findDuplicateDependencies(deps) {
|
|
546
|
+
const duplicates = [];
|
|
547
|
+
const seen = new Set();
|
|
548
|
+
for (const [name, version] of Object.entries(deps)) {
|
|
549
|
+
if (seen.has(name)) {
|
|
550
|
+
duplicates.push(name);
|
|
551
|
+
}
|
|
552
|
+
seen.add(name);
|
|
553
|
+
}
|
|
554
|
+
return duplicates;
|
|
555
|
+
}
|
|
556
|
+
addIssue(issue) {
|
|
557
|
+
this.issues.push(issue);
|
|
558
|
+
}
|
|
559
|
+
generateRecommendations() {
|
|
560
|
+
const recommendations = [];
|
|
561
|
+
if (this.metrics.packageJsonCount > 1) {
|
|
562
|
+
recommendations.push("Consolidate all dependencies into a single package.json file");
|
|
563
|
+
}
|
|
564
|
+
if (this.metrics.nodeModulesCount > 1) {
|
|
565
|
+
recommendations.push("Remove nested node_modules directories and reinstall dependencies");
|
|
566
|
+
}
|
|
567
|
+
if (this.metrics.lockFileCount > 1) {
|
|
568
|
+
recommendations.push("Use only pnpm-lock.yaml and remove other lock files");
|
|
569
|
+
}
|
|
570
|
+
if (this.metrics.projectDepth > 6) {
|
|
571
|
+
recommendations.push("Consider moving project to a shorter path");
|
|
572
|
+
}
|
|
573
|
+
if (this.projectRoot.includes(" ")) {
|
|
574
|
+
recommendations.push("Consider moving project to a path without spaces");
|
|
575
|
+
}
|
|
576
|
+
return recommendations;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Generate a comprehensive health report
|
|
580
|
+
*/
|
|
581
|
+
async generateHealthReport() {
|
|
582
|
+
const report = await this.validate();
|
|
583
|
+
let healthReport = `# Project Health Report\n\n`;
|
|
584
|
+
healthReport += `**Generated:** ${new Date().toISOString()}\n`;
|
|
585
|
+
healthReport += `**Project Root:** ${this.projectRoot}\n\n`;
|
|
586
|
+
healthReport += `## đ Metrics\n\n`;
|
|
587
|
+
healthReport += `- Package files: ${report.metrics.packageJsonCount}\n`;
|
|
588
|
+
healthReport += `- Node modules: ${report.metrics.nodeModulesCount}\n`;
|
|
589
|
+
healthReport += `- Lock files: ${report.metrics.lockFileCount}\n`;
|
|
590
|
+
healthReport += `- TypeScript configs: ${report.metrics.tsConfigCount}\n`;
|
|
591
|
+
healthReport += `- Build configs: ${report.metrics.buildConfigCount}\n`;
|
|
592
|
+
healthReport += `- Project depth: ${report.metrics.projectDepth}\n\n`;
|
|
593
|
+
healthReport += `## đĨ Health Status\n\n`;
|
|
594
|
+
healthReport += `**Overall Status:** ${report.isValid ? "â
HEALTHY" : "â NEEDS ATTENTION"}\n\n`;
|
|
595
|
+
if (report.issues.length > 0) {
|
|
596
|
+
healthReport += `## đ¨ Issues Found\n\n`;
|
|
597
|
+
const criticalIssues = report.issues.filter((i) => i.severity === "critical");
|
|
598
|
+
const highIssues = report.issues.filter((i) => i.severity === "high");
|
|
599
|
+
const mediumIssues = report.issues.filter((i) => i.severity === "medium");
|
|
600
|
+
const lowIssues = report.issues.filter((i) => i.severity === "low");
|
|
601
|
+
if (criticalIssues.length > 0) {
|
|
602
|
+
healthReport += `### Critical Issues\n\n`;
|
|
603
|
+
criticalIssues.forEach((issue) => {
|
|
604
|
+
healthReport += `- â **${issue.message}**\n`;
|
|
605
|
+
if (issue.file)
|
|
606
|
+
healthReport += ` - File: ${issue.file}\n`;
|
|
607
|
+
if (issue.fix)
|
|
608
|
+
healthReport += ` - Fix: ${issue.fix}\n`;
|
|
609
|
+
healthReport += `\n`;
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
if (highIssues.length > 0) {
|
|
613
|
+
healthReport += `### High Priority Issues\n\n`;
|
|
614
|
+
highIssues.forEach((issue) => {
|
|
615
|
+
healthReport += `- â ī¸ **${issue.message}**\n`;
|
|
616
|
+
if (issue.file)
|
|
617
|
+
healthReport += ` - File: ${issue.file}\n`;
|
|
618
|
+
if (issue.fix)
|
|
619
|
+
healthReport += ` - Fix: ${issue.fix}\n`;
|
|
620
|
+
healthReport += `\n`;
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
if (mediumIssues.length > 0) {
|
|
624
|
+
healthReport += `### Medium Priority Issues\n\n`;
|
|
625
|
+
mediumIssues.forEach((issue) => {
|
|
626
|
+
healthReport += `- â ī¸ **${issue.message}**\n`;
|
|
627
|
+
if (issue.file)
|
|
628
|
+
healthReport += ` - File: ${issue.file}\n`;
|
|
629
|
+
if (issue.fix)
|
|
630
|
+
healthReport += ` - Fix: ${issue.fix}\n`;
|
|
631
|
+
healthReport += `\n`;
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
if (lowIssues.length > 0) {
|
|
635
|
+
healthReport += `### Low Priority Issues\n\n`;
|
|
636
|
+
lowIssues.forEach((issue) => {
|
|
637
|
+
healthReport += `- âšī¸ **${issue.message}**\n`;
|
|
638
|
+
if (issue.file)
|
|
639
|
+
healthReport += ` - File: ${issue.file}\n`;
|
|
640
|
+
if (issue.fix)
|
|
641
|
+
healthReport += ` - Fix: ${issue.fix}\n`;
|
|
642
|
+
healthReport += `\n`;
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
if (report.recommendations.length > 0) {
|
|
647
|
+
healthReport += `## đĄ Recommendations\n\n`;
|
|
648
|
+
report.recommendations.forEach((rec) => {
|
|
649
|
+
healthReport += `- ${rec}\n`;
|
|
650
|
+
});
|
|
651
|
+
healthReport += `\n`;
|
|
652
|
+
}
|
|
653
|
+
healthReport += `## đ§ Auto-Fix Available\n\n`;
|
|
654
|
+
healthReport += `**Auto-fixable issues:** ${report.autoFixable ? "â
Yes" : "â No"}\n\n`;
|
|
655
|
+
if (report.autoFixable) {
|
|
656
|
+
healthReport += `Run \`mycontext health-check --fix\` to automatically fix issues.\n\n`;
|
|
657
|
+
}
|
|
658
|
+
return healthReport;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
exports.ProjectStructureValidator = ProjectStructureValidator;
|
|
662
|
+
//# sourceMappingURL=ProjectStructureValidator.js.map
|