mycontext-cli 2.0.2 → 2.0.4

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.
Files changed (69) hide show
  1. package/README.md +426 -103
  2. package/dist/README.md +426 -103
  3. package/dist/agents/implementations/ClaudeAgentWorkflow.d.ts.map +1 -1
  4. package/dist/agents/implementations/ClaudeAgentWorkflow.js +75 -4
  5. package/dist/agents/implementations/ClaudeAgentWorkflow.js.map +1 -1
  6. package/dist/agents/implementations/CodeGenSubAgent.d.ts.map +1 -1
  7. package/dist/agents/implementations/CodeGenSubAgent.js +69 -0
  8. package/dist/agents/implementations/CodeGenSubAgent.js.map +1 -1
  9. package/dist/agents/implementations/PromptConstructorAgent.d.ts.map +1 -1
  10. package/dist/agents/implementations/PromptConstructorAgent.js +23 -0
  11. package/dist/agents/implementations/PromptConstructorAgent.js.map +1 -1
  12. package/dist/agents/interfaces/SubAgent.d.ts +2 -0
  13. package/dist/agents/interfaces/SubAgent.d.ts.map +1 -1
  14. package/dist/cli.js +13 -40
  15. package/dist/cli.js.map +1 -1
  16. package/dist/commands/generate-components.d.ts +0 -5
  17. package/dist/commands/generate-components.d.ts.map +1 -1
  18. package/dist/commands/generate-components.js +0 -101
  19. package/dist/commands/generate-components.js.map +1 -1
  20. package/dist/commands/health-check.d.ts +28 -0
  21. package/dist/commands/health-check.d.ts.map +1 -0
  22. package/dist/commands/health-check.js +271 -0
  23. package/dist/commands/health-check.js.map +1 -0
  24. package/dist/commands/init.d.ts.map +1 -1
  25. package/dist/commands/init.js +2 -6
  26. package/dist/commands/init.js.map +1 -1
  27. package/dist/config/build-strategies.json +173 -22
  28. package/dist/package.json +2 -2
  29. package/dist/utils/NextJSProjectGenerator.d.ts +70 -0
  30. package/dist/utils/NextJSProjectGenerator.d.ts.map +1 -0
  31. package/dist/utils/NextJSProjectGenerator.js +811 -0
  32. package/dist/utils/NextJSProjectGenerator.js.map +1 -0
  33. package/dist/utils/NextJSProjectValidator.d.ts +103 -0
  34. package/dist/utils/NextJSProjectValidator.d.ts.map +1 -0
  35. package/dist/utils/NextJSProjectValidator.js +759 -0
  36. package/dist/utils/NextJSProjectValidator.js.map +1 -0
  37. package/dist/utils/PreCommandValidator.d.ts +77 -0
  38. package/dist/utils/PreCommandValidator.d.ts.map +1 -0
  39. package/dist/utils/PreCommandValidator.js +251 -0
  40. package/dist/utils/PreCommandValidator.js.map +1 -0
  41. package/dist/utils/ProjectHealthMonitor.d.ts +131 -0
  42. package/dist/utils/ProjectHealthMonitor.d.ts.map +1 -0
  43. package/dist/utils/ProjectHealthMonitor.js +454 -0
  44. package/dist/utils/ProjectHealthMonitor.js.map +1 -0
  45. package/dist/utils/ProjectInitializationSafeguards.d.ts +81 -0
  46. package/dist/utils/ProjectInitializationSafeguards.d.ts.map +1 -0
  47. package/dist/utils/ProjectInitializationSafeguards.js +620 -0
  48. package/dist/utils/ProjectInitializationSafeguards.js.map +1 -0
  49. package/dist/utils/ProjectStructureRepair.d.ts +110 -0
  50. package/dist/utils/ProjectStructureRepair.d.ts.map +1 -0
  51. package/dist/utils/ProjectStructureRepair.js +785 -0
  52. package/dist/utils/ProjectStructureRepair.js.map +1 -0
  53. package/dist/utils/ProjectStructureValidator.d.ts +128 -0
  54. package/dist/utils/ProjectStructureValidator.d.ts.map +1 -0
  55. package/dist/utils/ProjectStructureValidator.js +662 -0
  56. package/dist/utils/ProjectStructureValidator.js.map +1 -0
  57. package/dist/utils/agentDefinitions.d.ts +5 -0
  58. package/dist/utils/agentDefinitions.d.ts.map +1 -1
  59. package/dist/utils/agentDefinitions.js +99 -1
  60. package/dist/utils/agentDefinitions.js.map +1 -1
  61. package/dist/utils/mcpTools.d.ts +189 -0
  62. package/dist/utils/mcpTools.d.ts.map +1 -1
  63. package/dist/utils/mcpTools.js +462 -1
  64. package/dist/utils/mcpTools.js.map +1 -1
  65. package/package.json +2 -2
  66. package/dist/commands/core.d.ts +0 -24
  67. package/dist/commands/core.d.ts.map +0 -1
  68. package/dist/commands/core.js +0 -410
  69. package/dist/commands/core.js.map +0 -1
@@ -0,0 +1,759 @@
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.NextJSProjectValidator = void 0;
40
+ const fs = __importStar(require("fs-extra"));
41
+ const path = __importStar(require("path"));
42
+ const chalk_1 = __importDefault(require("chalk"));
43
+ const ProjectStructureValidator_1 = require("./ProjectStructureValidator");
44
+ class NextJSProjectValidator {
45
+ constructor(projectRoot = process.cwd()) {
46
+ this.projectRoot = projectRoot;
47
+ this.validator = new ProjectStructureValidator_1.ProjectStructureValidator(projectRoot);
48
+ }
49
+ /**
50
+ * Comprehensive Next.js project validation
51
+ */
52
+ async validateNextJSProject() {
53
+ console.log(chalk_1.default.blue("🔍 Validating Next.js project structure..."));
54
+ const issues = [];
55
+ // Run all Next.js specific validation checks
56
+ await this.validateAppRouterStructure(issues);
57
+ await this.validateLayoutFiles(issues);
58
+ await this.validatePageFiles(issues);
59
+ await this.validateComponentStructure(issues);
60
+ await this.validateShadcnIntegration(issues);
61
+ await this.validateNextJSConfiguration(issues);
62
+ await this.validateDependencies(issues);
63
+ const isValid = issues.filter((issue) => issue.type === "error").length === 0;
64
+ const appRouterCompliant = this.checkAppRouterCompliance(issues);
65
+ const shadcnCompliant = this.checkShadcnCompliance(issues);
66
+ return {
67
+ isValid,
68
+ issues,
69
+ recommendations: this.generateRecommendations(issues),
70
+ appRouterCompliant,
71
+ shadcnCompliant,
72
+ };
73
+ }
74
+ /**
75
+ * Validate App Router structure
76
+ */
77
+ async validateAppRouterStructure(issues) {
78
+ console.log(chalk_1.default.blue("📁 Validating App Router structure..."));
79
+ const appDir = path.join(this.projectRoot, "app");
80
+ // Check if app directory exists
81
+ if (!(await fs.pathExists(appDir))) {
82
+ issues.push({
83
+ type: "error",
84
+ severity: "critical",
85
+ message: "App Router directory 'app' not found. Next.js 13+ requires App Router structure.",
86
+ category: "routing",
87
+ autoFixable: true,
88
+ fix: "Create app directory with root layout.tsx and page.tsx",
89
+ });
90
+ return;
91
+ }
92
+ // Check for root layout.tsx
93
+ const rootLayoutPath = path.join(appDir, "layout.tsx");
94
+ if (!(await fs.pathExists(rootLayoutPath))) {
95
+ issues.push({
96
+ type: "error",
97
+ severity: "critical",
98
+ message: "Root layout.tsx not found in app directory",
99
+ file: rootLayoutPath,
100
+ category: "layout",
101
+ autoFixable: true,
102
+ fix: "Create root layout.tsx file",
103
+ });
104
+ }
105
+ // Check for root page.tsx
106
+ const rootPagePath = path.join(appDir, "page.tsx");
107
+ if (!(await fs.pathExists(rootPagePath))) {
108
+ issues.push({
109
+ type: "error",
110
+ severity: "critical",
111
+ message: "Root page.tsx not found in app directory",
112
+ file: rootPagePath,
113
+ category: "routing",
114
+ autoFixable: true,
115
+ fix: "Create root page.tsx file",
116
+ });
117
+ }
118
+ // Check for pages directory (conflict with App Router)
119
+ const pagesDir = path.join(this.projectRoot, "pages");
120
+ if (await fs.pathExists(pagesDir)) {
121
+ issues.push({
122
+ type: "warning",
123
+ severity: "high",
124
+ message: "Both 'app' and 'pages' directories found. This can cause routing conflicts.",
125
+ file: pagesDir,
126
+ category: "routing",
127
+ autoFixable: true,
128
+ fix: "Remove pages directory or migrate to App Router",
129
+ });
130
+ }
131
+ // Validate nested routes structure
132
+ await this.validateNestedRoutes(appDir, issues);
133
+ }
134
+ /**
135
+ * Validate nested routes structure
136
+ */
137
+ async validateNestedRoutes(appDir, issues) {
138
+ const routeDirs = await this.findRouteDirectories(appDir);
139
+ for (const routeDir of routeDirs) {
140
+ const relativePath = path.relative(appDir, routeDir);
141
+ // Check for page.tsx in route directories
142
+ const pagePath = path.join(routeDir, "page.tsx");
143
+ if (!(await fs.pathExists(pagePath))) {
144
+ issues.push({
145
+ type: "warning",
146
+ severity: "medium",
147
+ message: `Route directory '${relativePath}' missing page.tsx file`,
148
+ file: routeDir,
149
+ category: "routing",
150
+ autoFixable: true,
151
+ fix: `Create page.tsx in ${relativePath} directory`,
152
+ });
153
+ }
154
+ // Check for layout.tsx in route directories
155
+ const layoutPath = path.join(routeDir, "layout.tsx");
156
+ if (await fs.pathExists(layoutPath)) {
157
+ // Validate layout structure
158
+ await this.validateLayoutFile(layoutPath, issues);
159
+ }
160
+ }
161
+ }
162
+ /**
163
+ * Validate layout files
164
+ */
165
+ async validateLayoutFiles(issues) {
166
+ console.log(chalk_1.default.blue("🎨 Validating layout files..."));
167
+ const layoutFiles = await this.findFiles("**/layout.tsx");
168
+ for (const layoutFile of layoutFiles) {
169
+ await this.validateLayoutFile(layoutFile, issues);
170
+ }
171
+ }
172
+ /**
173
+ * Validate individual layout file
174
+ */
175
+ async validateLayoutFile(layoutPath, issues) {
176
+ try {
177
+ const content = await fs.readFile(layoutPath, "utf-8");
178
+ // Check for proper layout structure
179
+ if (!content.includes("children")) {
180
+ issues.push({
181
+ type: "warning",
182
+ severity: "medium",
183
+ message: "Layout file missing 'children' prop",
184
+ file: layoutPath,
185
+ category: "layout",
186
+ autoFixable: true,
187
+ fix: "Add children prop to layout component",
188
+ });
189
+ }
190
+ // Check for proper export
191
+ if (!content.includes("export default")) {
192
+ issues.push({
193
+ type: "error",
194
+ severity: "high",
195
+ message: "Layout file missing default export",
196
+ file: layoutPath,
197
+ category: "layout",
198
+ autoFixable: true,
199
+ fix: "Add default export to layout component",
200
+ });
201
+ }
202
+ // Check for metadata export (recommended)
203
+ if (!content.includes("export const metadata")) {
204
+ issues.push({
205
+ type: "info",
206
+ severity: "low",
207
+ message: "Layout file missing metadata export (recommended for SEO)",
208
+ file: layoutPath,
209
+ category: "layout",
210
+ autoFixable: true,
211
+ fix: "Add metadata export for better SEO",
212
+ });
213
+ }
214
+ }
215
+ catch (error) {
216
+ issues.push({
217
+ type: "error",
218
+ severity: "medium",
219
+ message: `Failed to read layout file: ${error}`,
220
+ file: layoutPath,
221
+ category: "layout",
222
+ autoFixable: false,
223
+ });
224
+ }
225
+ }
226
+ /**
227
+ * Validate page files
228
+ */
229
+ async validatePageFiles(issues) {
230
+ console.log(chalk_1.default.blue("📄 Validating page files..."));
231
+ const pageFiles = await this.findFiles("**/page.tsx");
232
+ for (const pageFile of pageFiles) {
233
+ await this.validatePageFile(pageFile, issues);
234
+ }
235
+ }
236
+ /**
237
+ * Validate individual page file
238
+ */
239
+ async validatePageFile(pagePath, issues) {
240
+ try {
241
+ const content = await fs.readFile(pagePath, "utf-8");
242
+ // Check for proper export
243
+ if (!content.includes("export default")) {
244
+ issues.push({
245
+ type: "error",
246
+ severity: "high",
247
+ message: "Page file missing default export",
248
+ file: pagePath,
249
+ category: "routing",
250
+ autoFixable: true,
251
+ fix: "Add default export to page component",
252
+ });
253
+ }
254
+ // Check for metadata export (recommended)
255
+ if (!content.includes("export const metadata")) {
256
+ issues.push({
257
+ type: "info",
258
+ severity: "low",
259
+ message: "Page file missing metadata export (recommended for SEO)",
260
+ file: pagePath,
261
+ category: "routing",
262
+ autoFixable: true,
263
+ fix: "Add metadata export for better SEO",
264
+ });
265
+ }
266
+ // Check for proper component structure
267
+ if (!content.includes("function") &&
268
+ !content.includes("const") &&
269
+ !content.includes("=>")) {
270
+ issues.push({
271
+ type: "warning",
272
+ severity: "medium",
273
+ message: "Page file doesn't appear to contain a React component",
274
+ file: pagePath,
275
+ category: "routing",
276
+ autoFixable: false,
277
+ });
278
+ }
279
+ }
280
+ catch (error) {
281
+ issues.push({
282
+ type: "error",
283
+ severity: "medium",
284
+ message: `Failed to read page file: ${error}`,
285
+ file: pagePath,
286
+ category: "routing",
287
+ autoFixable: false,
288
+ });
289
+ }
290
+ }
291
+ /**
292
+ * Validate component structure
293
+ */
294
+ async validateComponentStructure(issues) {
295
+ console.log(chalk_1.default.blue("🧩 Validating component structure..."));
296
+ // Check for components directory
297
+ const componentsDir = path.join(this.projectRoot, "components");
298
+ if (!(await fs.pathExists(componentsDir))) {
299
+ issues.push({
300
+ type: "warning",
301
+ severity: "medium",
302
+ message: "Components directory not found",
303
+ category: "components",
304
+ autoFixable: true,
305
+ fix: "Create components directory for reusable components",
306
+ });
307
+ }
308
+ // Check for UI components directory (shadcn/ui pattern)
309
+ const uiDir = path.join(this.projectRoot, "components", "ui");
310
+ if (!(await fs.pathExists(uiDir))) {
311
+ issues.push({
312
+ type: "info",
313
+ severity: "low",
314
+ message: "UI components directory not found (recommended for shadcn/ui)",
315
+ category: "components",
316
+ autoFixable: true,
317
+ fix: "Create components/ui directory for shadcn/ui components",
318
+ });
319
+ }
320
+ // Validate component files
321
+ const componentFiles = await this.findFiles("**/*.tsx");
322
+ for (const componentFile of componentFiles) {
323
+ if (!componentFile.includes("page.tsx") &&
324
+ !componentFile.includes("layout.tsx")) {
325
+ await this.validateComponentFile(componentFile, issues);
326
+ }
327
+ }
328
+ }
329
+ /**
330
+ * Validate individual component file
331
+ */
332
+ async validateComponentFile(componentPath, issues) {
333
+ try {
334
+ const content = await fs.readFile(componentPath, "utf-8");
335
+ // Check for proper export
336
+ if (!content.includes("export")) {
337
+ issues.push({
338
+ type: "warning",
339
+ severity: "medium",
340
+ message: "Component file missing export statement",
341
+ file: componentPath,
342
+ category: "components",
343
+ autoFixable: false,
344
+ });
345
+ }
346
+ // Check for TypeScript types
347
+ if (!content.includes("interface") &&
348
+ !content.includes("type") &&
349
+ !content.includes("Props")) {
350
+ issues.push({
351
+ type: "info",
352
+ severity: "low",
353
+ message: "Component file missing TypeScript prop types",
354
+ file: componentPath,
355
+ category: "components",
356
+ autoFixable: true,
357
+ fix: "Add TypeScript prop interface",
358
+ });
359
+ }
360
+ }
361
+ catch (error) {
362
+ issues.push({
363
+ type: "error",
364
+ severity: "medium",
365
+ message: `Failed to read component file: ${error}`,
366
+ file: componentPath,
367
+ category: "components",
368
+ autoFixable: false,
369
+ });
370
+ }
371
+ }
372
+ /**
373
+ * Validate shadcn/ui integration
374
+ */
375
+ async validateShadcnIntegration(issues) {
376
+ console.log(chalk_1.default.blue("🎨 Validating shadcn/ui integration..."));
377
+ // Check for components.json
378
+ const componentsJsonPath = path.join(this.projectRoot, "components.json");
379
+ if (!(await fs.pathExists(componentsJsonPath))) {
380
+ issues.push({
381
+ type: "warning",
382
+ severity: "medium",
383
+ message: "components.json not found (required for shadcn/ui)",
384
+ category: "configuration",
385
+ autoFixable: true,
386
+ fix: "Run 'pnpm dlx shadcn@latest init' to setup shadcn/ui",
387
+ });
388
+ }
389
+ else {
390
+ // Validate components.json content
391
+ await this.validateComponentsJson(componentsJsonPath, issues);
392
+ }
393
+ // Check for lib/utils.ts
394
+ const utilsPath = path.join(this.projectRoot, "lib", "utils.ts");
395
+ if (!(await fs.pathExists(utilsPath))) {
396
+ issues.push({
397
+ type: "warning",
398
+ severity: "medium",
399
+ message: "lib/utils.ts not found (required for shadcn/ui)",
400
+ category: "configuration",
401
+ autoFixable: true,
402
+ fix: "Create lib/utils.ts with cn utility function",
403
+ });
404
+ }
405
+ // Check for Tailwind CSS configuration
406
+ const tailwindConfigPath = path.join(this.projectRoot, "tailwind.config.ts");
407
+ if (!(await fs.pathExists(tailwindConfigPath))) {
408
+ issues.push({
409
+ type: "warning",
410
+ severity: "medium",
411
+ message: "Tailwind CSS configuration not found (required for shadcn/ui)",
412
+ category: "configuration",
413
+ autoFixable: true,
414
+ fix: "Create tailwind.config.ts for shadcn/ui",
415
+ });
416
+ }
417
+ // Check for CSS variables
418
+ const globalCssPath = path.join(this.projectRoot, "app", "globals.css");
419
+ if (await fs.pathExists(globalCssPath)) {
420
+ await this.validateGlobalCSS(globalCssPath, issues);
421
+ }
422
+ }
423
+ /**
424
+ * Validate components.json
425
+ */
426
+ async validateComponentsJson(componentsJsonPath, issues) {
427
+ try {
428
+ const content = await fs.readJson(componentsJsonPath);
429
+ // Check required fields
430
+ if (!content.style) {
431
+ issues.push({
432
+ type: "warning",
433
+ severity: "medium",
434
+ message: "components.json missing 'style' field",
435
+ file: componentsJsonPath,
436
+ category: "configuration",
437
+ autoFixable: true,
438
+ fix: "Add style field to components.json",
439
+ });
440
+ }
441
+ if (!content.rsc) {
442
+ issues.push({
443
+ type: "warning",
444
+ severity: "medium",
445
+ message: "components.json missing 'rsc' field (React Server Components)",
446
+ file: componentsJsonPath,
447
+ category: "configuration",
448
+ autoFixable: true,
449
+ fix: "Add rsc: true to components.json",
450
+ });
451
+ }
452
+ if (!content.tsx) {
453
+ issues.push({
454
+ type: "warning",
455
+ severity: "medium",
456
+ message: "components.json missing 'tsx' field",
457
+ file: componentsJsonPath,
458
+ category: "configuration",
459
+ autoFixable: true,
460
+ fix: "Add tsx: true to components.json",
461
+ });
462
+ }
463
+ }
464
+ catch (error) {
465
+ issues.push({
466
+ type: "error",
467
+ severity: "medium",
468
+ message: `Failed to read components.json: ${error}`,
469
+ file: componentsJsonPath,
470
+ category: "configuration",
471
+ autoFixable: false,
472
+ });
473
+ }
474
+ }
475
+ /**
476
+ * Validate global CSS
477
+ */
478
+ async validateGlobalCSS(globalCssPath, issues) {
479
+ try {
480
+ const content = await fs.readFile(globalCssPath, "utf-8");
481
+ // Check for CSS variables
482
+ if (!content.includes("--background") ||
483
+ !content.includes("--foreground")) {
484
+ issues.push({
485
+ type: "warning",
486
+ severity: "medium",
487
+ message: "Global CSS missing shadcn/ui CSS variables",
488
+ file: globalCssPath,
489
+ category: "configuration",
490
+ autoFixable: true,
491
+ fix: "Add shadcn/ui CSS variables to globals.css",
492
+ });
493
+ }
494
+ // Check for Tailwind directives
495
+ if (!content.includes("@tailwind base") ||
496
+ !content.includes("@tailwind components")) {
497
+ issues.push({
498
+ type: "warning",
499
+ severity: "medium",
500
+ message: "Global CSS missing Tailwind directives",
501
+ file: globalCssPath,
502
+ category: "configuration",
503
+ autoFixable: true,
504
+ fix: "Add Tailwind directives to globals.css",
505
+ });
506
+ }
507
+ }
508
+ catch (error) {
509
+ issues.push({
510
+ type: "error",
511
+ severity: "medium",
512
+ message: `Failed to read global CSS: ${error}`,
513
+ file: globalCssPath,
514
+ category: "configuration",
515
+ autoFixable: false,
516
+ });
517
+ }
518
+ }
519
+ /**
520
+ * Validate Next.js configuration
521
+ */
522
+ async validateNextJSConfiguration(issues) {
523
+ console.log(chalk_1.default.blue("⚙️ Validating Next.js configuration..."));
524
+ const nextConfigPath = path.join(this.projectRoot, "next.config.ts");
525
+ if (await fs.pathExists(nextConfigPath)) {
526
+ await this.validateNextConfig(nextConfigPath, issues);
527
+ }
528
+ // Check for TypeScript configuration
529
+ const tsConfigPath = path.join(this.projectRoot, "tsconfig.json");
530
+ if (await fs.pathExists(tsConfigPath)) {
531
+ await this.validateTsConfig(tsConfigPath, issues);
532
+ }
533
+ }
534
+ /**
535
+ * Validate Next.js config
536
+ */
537
+ async validateNextConfig(nextConfigPath, issues) {
538
+ try {
539
+ const content = await fs.readFile(nextConfigPath, "utf-8");
540
+ // Check for proper TypeScript configuration
541
+ if (!content.includes("NextConfig")) {
542
+ issues.push({
543
+ type: "warning",
544
+ severity: "low",
545
+ message: "Next.js config missing TypeScript types",
546
+ file: nextConfigPath,
547
+ category: "configuration",
548
+ autoFixable: true,
549
+ fix: "Add NextConfig type import",
550
+ });
551
+ }
552
+ // Check for experimental features
553
+ if (!content.includes("experimental")) {
554
+ issues.push({
555
+ type: "info",
556
+ severity: "low",
557
+ message: "Next.js config missing experimental features (turbo, etc.)",
558
+ file: nextConfigPath,
559
+ category: "configuration",
560
+ autoFixable: true,
561
+ fix: "Add experimental features for better performance",
562
+ });
563
+ }
564
+ }
565
+ catch (error) {
566
+ issues.push({
567
+ type: "error",
568
+ severity: "medium",
569
+ message: `Failed to read Next.js config: ${error}`,
570
+ file: nextConfigPath,
571
+ category: "configuration",
572
+ autoFixable: false,
573
+ });
574
+ }
575
+ }
576
+ /**
577
+ * Validate TypeScript configuration
578
+ */
579
+ async validateTsConfig(tsConfigPath, issues) {
580
+ try {
581
+ const content = await fs.readJson(tsConfigPath);
582
+ // Check for proper Next.js TypeScript configuration
583
+ if (!content.compilerOptions?.plugins?.some((plugin) => plugin.name === "next")) {
584
+ issues.push({
585
+ type: "warning",
586
+ severity: "medium",
587
+ message: "TypeScript config missing Next.js plugin",
588
+ file: tsConfigPath,
589
+ category: "configuration",
590
+ autoFixable: true,
591
+ fix: "Add Next.js plugin to TypeScript config",
592
+ });
593
+ }
594
+ // Check for path mapping
595
+ if (!content.compilerOptions?.paths?.["@/*"]) {
596
+ issues.push({
597
+ type: "warning",
598
+ severity: "medium",
599
+ message: "TypeScript config missing path mapping for @/*",
600
+ file: tsConfigPath,
601
+ category: "configuration",
602
+ autoFixable: true,
603
+ fix: "Add @/* path mapping to TypeScript config",
604
+ });
605
+ }
606
+ }
607
+ catch (error) {
608
+ issues.push({
609
+ type: "error",
610
+ severity: "medium",
611
+ message: `Failed to read TypeScript config: ${error}`,
612
+ file: tsConfigPath,
613
+ category: "configuration",
614
+ autoFixable: false,
615
+ });
616
+ }
617
+ }
618
+ /**
619
+ * Validate dependencies
620
+ */
621
+ async validateDependencies(issues) {
622
+ console.log(chalk_1.default.blue("📦 Validating dependencies..."));
623
+ const packageJsonPath = path.join(this.projectRoot, "package.json");
624
+ if (!(await fs.pathExists(packageJsonPath))) {
625
+ return;
626
+ }
627
+ try {
628
+ const packageJson = await fs.readJson(packageJsonPath);
629
+ const dependencies = {
630
+ ...packageJson.dependencies,
631
+ ...packageJson.devDependencies,
632
+ };
633
+ // Check for Next.js
634
+ if (!dependencies.next) {
635
+ issues.push({
636
+ type: "error",
637
+ severity: "critical",
638
+ message: "Next.js not found in dependencies",
639
+ category: "dependencies",
640
+ autoFixable: true,
641
+ fix: "Install Next.js: pnpm add next",
642
+ });
643
+ }
644
+ // Check for React
645
+ if (!dependencies.react || !dependencies["react-dom"]) {
646
+ issues.push({
647
+ type: "error",
648
+ severity: "critical",
649
+ message: "React dependencies missing",
650
+ category: "dependencies",
651
+ autoFixable: true,
652
+ fix: "Install React: pnpm add react react-dom",
653
+ });
654
+ }
655
+ // Check for TypeScript
656
+ if (!dependencies.typescript) {
657
+ issues.push({
658
+ type: "warning",
659
+ severity: "medium",
660
+ message: "TypeScript not found in devDependencies",
661
+ category: "dependencies",
662
+ autoFixable: true,
663
+ fix: "Install TypeScript: pnpm add -D typescript @types/react @types/node",
664
+ });
665
+ }
666
+ // Check for Tailwind CSS (if shadcn/ui is expected)
667
+ if (await fs.pathExists(path.join(this.projectRoot, "components.json"))) {
668
+ if (!dependencies.tailwindcss) {
669
+ issues.push({
670
+ type: "warning",
671
+ severity: "medium",
672
+ message: "Tailwind CSS not found (required for shadcn/ui)",
673
+ category: "dependencies",
674
+ autoFixable: true,
675
+ fix: "Install Tailwind CSS: pnpm add -D tailwindcss autoprefixer postcss",
676
+ });
677
+ }
678
+ }
679
+ }
680
+ catch (error) {
681
+ issues.push({
682
+ type: "error",
683
+ severity: "medium",
684
+ message: `Failed to read package.json: ${error}`,
685
+ file: packageJsonPath,
686
+ category: "dependencies",
687
+ autoFixable: false,
688
+ });
689
+ }
690
+ }
691
+ /**
692
+ * Check App Router compliance
693
+ */
694
+ checkAppRouterCompliance(issues) {
695
+ const criticalIssues = issues.filter((issue) => issue.category === "routing" && issue.severity === "critical");
696
+ return criticalIssues.length === 0;
697
+ }
698
+ /**
699
+ * Check shadcn/ui compliance
700
+ */
701
+ checkShadcnCompliance(issues) {
702
+ const shadcnIssues = issues.filter((issue) => issue.message.includes("shadcn") ||
703
+ issue.message.includes("components.json") ||
704
+ issue.message.includes("Tailwind"));
705
+ return shadcnIssues.length === 0;
706
+ }
707
+ /**
708
+ * Generate recommendations
709
+ */
710
+ generateRecommendations(issues) {
711
+ const recommendations = [];
712
+ const criticalIssues = issues.filter((issue) => issue.severity === "critical");
713
+ if (criticalIssues.length > 0) {
714
+ recommendations.push("Address critical issues immediately to ensure proper Next.js functionality");
715
+ }
716
+ const routingIssues = issues.filter((issue) => issue.category === "routing");
717
+ if (routingIssues.length > 0) {
718
+ recommendations.push("Review App Router structure and ensure proper page.tsx and layout.tsx files");
719
+ }
720
+ const shadcnIssues = issues.filter((issue) => issue.message.includes("shadcn"));
721
+ if (shadcnIssues.length > 0) {
722
+ recommendations.push("Run 'pnpm dlx shadcn@latest init' to properly setup shadcn/ui");
723
+ }
724
+ const configIssues = issues.filter((issue) => issue.category === "configuration");
725
+ if (configIssues.length > 0) {
726
+ recommendations.push("Update configuration files to follow Next.js 13+ best practices");
727
+ }
728
+ return recommendations;
729
+ }
730
+ /**
731
+ * Helper methods
732
+ */
733
+ async findFiles(pattern) {
734
+ const glob = require("glob");
735
+ const matches = await glob(pattern, {
736
+ cwd: this.projectRoot,
737
+ absolute: true,
738
+ ignore: ["**/node_modules/**"],
739
+ });
740
+ return matches;
741
+ }
742
+ async findRouteDirectories(appDir) {
743
+ const routeDirs = [];
744
+ const findDirs = async (dir) => {
745
+ const entries = await fs.readdir(dir, { withFileTypes: true });
746
+ for (const entry of entries) {
747
+ if (entry.isDirectory()) {
748
+ const fullPath = path.join(dir, entry.name);
749
+ routeDirs.push(fullPath);
750
+ await findDirs(fullPath);
751
+ }
752
+ }
753
+ };
754
+ await findDirs(appDir);
755
+ return routeDirs;
756
+ }
757
+ }
758
+ exports.NextJSProjectValidator = NextJSProjectValidator;
759
+ //# sourceMappingURL=NextJSProjectValidator.js.map