stackkit 0.1.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.
Files changed (121) hide show
  1. package/README.md +41 -0
  2. package/bin/stackkit.js +4 -0
  3. package/dist/cli/add.d.ts +8 -0
  4. package/dist/cli/add.js +313 -0
  5. package/dist/cli/create.d.ts +22 -0
  6. package/dist/cli/create.js +336 -0
  7. package/dist/cli/doctor.d.ts +7 -0
  8. package/dist/cli/doctor.js +569 -0
  9. package/dist/cli/list.d.ts +6 -0
  10. package/dist/cli/list.js +123 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.js +91 -0
  13. package/dist/lib/conversion/js-conversion.d.ts +1 -0
  14. package/dist/lib/conversion/js-conversion.js +244 -0
  15. package/dist/lib/database/database-config.d.ts +6 -0
  16. package/dist/lib/database/database-config.js +9 -0
  17. package/dist/lib/discovery/module-discovery.d.ts +62 -0
  18. package/dist/lib/discovery/module-discovery.js +188 -0
  19. package/dist/lib/env/env-editor.d.ts +9 -0
  20. package/dist/lib/env/env-editor.js +116 -0
  21. package/dist/lib/framework/framework-utils.d.ts +22 -0
  22. package/dist/lib/framework/framework-utils.js +74 -0
  23. package/dist/lib/fs/files.d.ts +14 -0
  24. package/dist/lib/fs/files.js +101 -0
  25. package/dist/lib/generation/code-generator.d.ts +83 -0
  26. package/dist/lib/generation/code-generator.js +681 -0
  27. package/dist/lib/git-utils.d.ts +1 -0
  28. package/dist/lib/git-utils.js +9 -0
  29. package/dist/lib/pm/package-manager.d.ts +5 -0
  30. package/dist/lib/pm/package-manager.js +69 -0
  31. package/dist/lib/project/detect.d.ts +4 -0
  32. package/dist/lib/project/detect.js +121 -0
  33. package/dist/lib/ui/logger.d.ts +16 -0
  34. package/dist/lib/ui/logger.js +59 -0
  35. package/dist/types/index.d.ts +92 -0
  36. package/dist/types/index.js +2 -0
  37. package/modules/auth/authjs/files/api/auth/[...nextauth]/route.ts +6 -0
  38. package/modules/auth/authjs/files/lib/auth-client.ts +11 -0
  39. package/modules/auth/authjs/files/lib/auth.ts +36 -0
  40. package/modules/auth/authjs/files/schemas/prisma-schema.prisma +45 -0
  41. package/modules/auth/authjs/module.json +22 -0
  42. package/modules/auth/better-auth/files/api/auth/[...all]/route.ts +4 -0
  43. package/modules/auth/better-auth/files/lib/auth-client.ts +7 -0
  44. package/modules/auth/better-auth/files/lib/auth.ts +83 -0
  45. package/modules/auth/better-auth/files/lib/email-service.ts +34 -0
  46. package/modules/auth/better-auth/files/lib/email-templates.ts +89 -0
  47. package/modules/auth/better-auth/files/prisma/schema.prisma +63 -0
  48. package/modules/auth/better-auth/generator.json +78 -0
  49. package/modules/auth/better-auth/module.json +37 -0
  50. package/modules/database/mongoose/files/lib/db.ts +63 -0
  51. package/modules/database/mongoose/files/models/User.ts +34 -0
  52. package/modules/database/mongoose/generator.json +24 -0
  53. package/modules/database/mongoose/module.json +15 -0
  54. package/modules/database/prisma/files/lib/prisma.ts +45 -0
  55. package/modules/database/prisma/files/prisma/schema.prisma +8 -0
  56. package/modules/database/prisma/files/prisma.config.ts +12 -0
  57. package/modules/database/prisma/generator.json +43 -0
  58. package/modules/database/prisma/module.json +17 -0
  59. package/package.json +83 -0
  60. package/templates/express/.env.example +2 -0
  61. package/templates/express/eslint.config.cjs +42 -0
  62. package/templates/express/package.json +33 -0
  63. package/templates/express/src/app.ts +51 -0
  64. package/templates/express/src/config/env.ts +12 -0
  65. package/templates/express/src/features/health/health.controller.ts +18 -0
  66. package/templates/express/src/features/health/health.route.ts +9 -0
  67. package/templates/express/src/features/health/health.service.ts +6 -0
  68. package/templates/express/src/middlewares/error.middleware.ts +18 -0
  69. package/templates/express/src/server.ts +8 -0
  70. package/templates/express/template.json +27 -0
  71. package/templates/express/tsconfig.json +30 -0
  72. package/templates/nextjs/README.md +52 -0
  73. package/templates/nextjs/app/favicon.ico +0 -0
  74. package/templates/nextjs/app/globals.css +26 -0
  75. package/templates/nextjs/app/layout.tsx +30 -0
  76. package/templates/nextjs/app/page.tsx +57 -0
  77. package/templates/nextjs/eslint.config.mjs +18 -0
  78. package/templates/nextjs/lib/env.ts +8 -0
  79. package/templates/nextjs/next.config.ts +7 -0
  80. package/templates/nextjs/package.json +27 -0
  81. package/templates/nextjs/postcss.config.mjs +7 -0
  82. package/templates/nextjs/public/file.svg +1 -0
  83. package/templates/nextjs/public/globe.svg +1 -0
  84. package/templates/nextjs/public/next.svg +1 -0
  85. package/templates/nextjs/public/vercel.svg +1 -0
  86. package/templates/nextjs/public/window.svg +1 -0
  87. package/templates/nextjs/template.json +34 -0
  88. package/templates/nextjs/tsconfig.json +34 -0
  89. package/templates/react/.env.example +1 -0
  90. package/templates/react/.prettierignore +4 -0
  91. package/templates/react/.prettierrc +9 -0
  92. package/templates/react/README.md +56 -0
  93. package/templates/react/eslint.config.js +23 -0
  94. package/templates/react/index.html +14 -0
  95. package/templates/react/package.json +44 -0
  96. package/templates/react/public/vite.svg +1 -0
  97. package/templates/react/src/api/client.ts +47 -0
  98. package/templates/react/src/assets/react.svg +1 -0
  99. package/templates/react/src/components/ErrorBoundary.tsx +51 -0
  100. package/templates/react/src/components/Layout.tsx +13 -0
  101. package/templates/react/src/components/Loading.tsx +8 -0
  102. package/templates/react/src/components/SEO.tsx +49 -0
  103. package/templates/react/src/config/constants.ts +5 -0
  104. package/templates/react/src/hooks/index.ts +64 -0
  105. package/templates/react/src/index.css +1 -0
  106. package/templates/react/src/lib/queryClient.ts +12 -0
  107. package/templates/react/src/main.tsx +22 -0
  108. package/templates/react/src/pages/About.tsx +78 -0
  109. package/templates/react/src/pages/Home.tsx +49 -0
  110. package/templates/react/src/pages/NotFound.tsx +24 -0
  111. package/templates/react/src/router.tsx +21 -0
  112. package/templates/react/src/types/api.d.ts +20 -0
  113. package/templates/react/src/utils/helpers.ts +51 -0
  114. package/templates/react/src/utils/storage.ts +35 -0
  115. package/templates/react/src/vite-env.d.ts +11 -0
  116. package/templates/react/template.json +38 -0
  117. package/templates/react/tsconfig.app.json +28 -0
  118. package/templates/react/tsconfig.json +4 -0
  119. package/templates/react/tsconfig.node.json +26 -0
  120. package/templates/react/vite.config.ts +7 -0
  121. package/templates/react-vite/README.md +56 -0
@@ -0,0 +1,569 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.doctorCommand = doctorCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const logger_1 = require("../lib/ui/logger");
11
+ // Constants for consistent messaging
12
+ const MESSAGES = {
13
+ NO_PACKAGE_JSON: "No package.json found in current directory or any parent directory.",
14
+ UNSUPPORTED_PROJECT: "Unsupported project type. Only Next.js, Express, and React projects are supported.",
15
+ NODE_TOO_OLD: (version) => `Node.js version ${version} is not supported. Minimum required: Node 18.`,
16
+ NODE_WARNING: (version) => `Node.js version ${version} is supported but Node 20+ is recommended.`,
17
+ NODE_SUCCESS: (version) => `Node.js version ${version} is supported.`,
18
+ ENV_EXAMPLE_MISSING: ".env.example file missing (recommended for documentation)",
19
+ ENV_EXAMPLE_FOUND: ".env.example file found",
20
+ ENV_MISSING: "No .env or .env.local file found",
21
+ ENV_FOUND: ".env/.env.local file found",
22
+ PRISMA_SCHEMA_MISSING: "Prisma schema missing (required for Prisma)",
23
+ PRISMA_SCHEMA_FOUND: "Prisma schema found",
24
+ AUTH_ROUTES_MISSING: "Auth routes not found (may need configuration)",
25
+ AUTH_ROUTES_FOUND: "Auth routes configured",
26
+ ENV_VARS_MISSING: (vars) => `Missing: ${vars.join(", ")}`,
27
+ ENV_VARS_PRESENT: (vars) => `Present: ${vars.join(", ")}`,
28
+ TSCONFIG_MISSING: "tsconfig.json missing (required for TypeScript)",
29
+ TSCONFIG_FOUND: "tsconfig.json found",
30
+ ESLINT_CONFIG_MISSING: "ESLint config missing (recommended for code quality)",
31
+ ESLINT_CONFIG_FOUND: "ESLint config found",
32
+ BUILD_SCRIPT_MISSING: "Build script missing in package.json",
33
+ BUILD_SCRIPT_FOUND: "Build script found",
34
+ DEPENDENCY_OUTDATED: (deps) => `Outdated dependencies: ${deps.join(", ")}`,
35
+ DEPENDENCY_UP_TO_DATE: "Dependencies are up to date",
36
+ GIT_REPO_MISSING: "Not a git repository (recommended for version control)",
37
+ GIT_REPO_FOUND: "Git repository initialized",
38
+ };
39
+ async function doctorCommand(options) {
40
+ try {
41
+ const report = await runDoctorChecks();
42
+ if (options.json) {
43
+ process.stdout.write(JSON.stringify(report, null, 2) + "\n");
44
+ return;
45
+ }
46
+ printDoctorReport(report, options.verbose || false);
47
+ const hasErrors = report.summary.errors > 0;
48
+ const hasWarnings = report.summary.warnings > 0;
49
+ const strictMode = options.strict || false;
50
+ if (hasErrors || (strictMode && hasWarnings)) {
51
+ process.exit(1);
52
+ }
53
+ else {
54
+ process.exit(0);
55
+ }
56
+ }
57
+ catch (error) {
58
+ logger_1.logger.error(`Doctor check failed: ${error instanceof Error ? error.message : String(error)}`);
59
+ process.exit(1);
60
+ }
61
+ }
62
+ async function runDoctorChecks() {
63
+ const checks = [];
64
+ const projectRoot = await findProjectRoot();
65
+ checks.push({
66
+ status: "success",
67
+ message: `Found project root: ${projectRoot}`,
68
+ });
69
+ const packageJson = await readPackageJson(projectRoot);
70
+ const packageManager = await detectPackageManager(projectRoot);
71
+ const projectType = detectProjectType(packageJson);
72
+ if (projectType === "unknown") {
73
+ checks.push({
74
+ status: "error",
75
+ message: MESSAGES.UNSUPPORTED_PROJECT,
76
+ });
77
+ }
78
+ else {
79
+ checks.push({
80
+ status: "success",
81
+ message: `Detected project type: ${projectType}`,
82
+ });
83
+ }
84
+ const nodeVersionCheck = checkNodeVersion();
85
+ checks.push(nodeVersionCheck);
86
+ const authModules = detectAuthModules(packageJson);
87
+ const databaseModules = detectDatabaseModules(packageJson);
88
+ const filesCheck = await checkKeyFiles(projectRoot, projectType, authModules, databaseModules);
89
+ checks.push(...filesCheck);
90
+ const envCheck = await checkEnvFiles(projectRoot, authModules, databaseModules);
91
+ checks.push(...envCheck.checks);
92
+ const configChecks = await checkConfigFiles(projectRoot, projectType, packageJson);
93
+ checks.push(...configChecks);
94
+ const dependencyCheck = await checkDependencies(packageJson);
95
+ checks.push(dependencyCheck);
96
+ const gitCheck = await checkGitRepo(projectRoot);
97
+ checks.push(gitCheck);
98
+ const conflicts = checkConflicts(authModules, databaseModules);
99
+ conflicts.forEach(conflict => {
100
+ checks.push({
101
+ status: "warning",
102
+ message: conflict,
103
+ });
104
+ });
105
+ const report = {
106
+ project: {
107
+ type: projectType,
108
+ root: projectRoot,
109
+ packageManager,
110
+ },
111
+ runtime: {
112
+ nodeVersion: process.version,
113
+ nodeVersionStatus: nodeVersionCheck.status,
114
+ },
115
+ modules: {
116
+ auth: authModules,
117
+ database: databaseModules,
118
+ },
119
+ files: {
120
+ envExample: await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, ".env.example")),
121
+ env: await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, ".env")) || await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, ".env.local")),
122
+ prismaSchema: databaseModules.includes("prisma") ? await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, "prisma", "schema.prisma")) : undefined,
123
+ authRoutes: authModules.length > 0 ? await checkAuthRoutesExist(projectRoot, projectType) : undefined,
124
+ tsconfig: await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, "tsconfig.json")),
125
+ eslintConfig: await checkEslintConfigExists(projectRoot),
126
+ git: await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, ".git")),
127
+ },
128
+ env: envCheck.envStatus,
129
+ dependencies: {
130
+ outdated: dependencyCheck.outdated,
131
+ },
132
+ conflicts,
133
+ checks,
134
+ summary: {
135
+ errors: checks.filter(c => c.status === "error").length,
136
+ warnings: checks.filter(c => c.status === "warning").length,
137
+ suggestions: generateSuggestions(),
138
+ },
139
+ };
140
+ return report;
141
+ }
142
+ async function findProjectRoot() {
143
+ let currentDir = process.cwd();
144
+ while (currentDir !== path_1.default.dirname(currentDir)) {
145
+ const packageJsonPath = path_1.default.join(currentDir, "package.json");
146
+ if (await fs_extra_1.default.pathExists(packageJsonPath)) {
147
+ return currentDir;
148
+ }
149
+ currentDir = path_1.default.dirname(currentDir);
150
+ }
151
+ throw new Error(MESSAGES.NO_PACKAGE_JSON);
152
+ }
153
+ async function readPackageJson(projectRoot) {
154
+ const packageJsonPath = path_1.default.join(projectRoot, "package.json");
155
+ return await fs_extra_1.default.readJSON(packageJsonPath);
156
+ }
157
+ async function detectPackageManager(projectRoot) {
158
+ const checks = [
159
+ { file: "pnpm-lock.yaml", manager: "pnpm" },
160
+ { file: "yarn.lock", manager: "yarn" },
161
+ { file: "package-lock.json", manager: "npm" },
162
+ ];
163
+ for (const check of checks) {
164
+ if (await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, check.file))) {
165
+ return check.manager;
166
+ }
167
+ }
168
+ return "npm";
169
+ }
170
+ function detectProjectType(packageJson) {
171
+ const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
172
+ if (deps.next) {
173
+ return "nextjs";
174
+ }
175
+ else if (deps.express) {
176
+ return "express";
177
+ }
178
+ else if (deps.vite && deps.react) {
179
+ return "react";
180
+ }
181
+ else if (deps.react) {
182
+ return "react";
183
+ }
184
+ return "unknown";
185
+ }
186
+ function checkNodeVersion() {
187
+ const version = process.version;
188
+ const majorVersion = parseInt(version.slice(1).split(".")[0]);
189
+ if (majorVersion < 18) {
190
+ return {
191
+ status: "error",
192
+ message: MESSAGES.NODE_TOO_OLD(version),
193
+ };
194
+ }
195
+ else if (majorVersion < 20) {
196
+ return {
197
+ status: "warning",
198
+ message: MESSAGES.NODE_WARNING(version),
199
+ };
200
+ }
201
+ else {
202
+ return {
203
+ status: "success",
204
+ message: MESSAGES.NODE_SUCCESS(version),
205
+ };
206
+ }
207
+ }
208
+ function detectAuthModules(packageJson) {
209
+ const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
210
+ const modules = [];
211
+ if (deps["better-auth"]) {
212
+ modules.push("better-auth");
213
+ }
214
+ if (deps["next-auth"]) {
215
+ modules.push("authjs");
216
+ }
217
+ return modules;
218
+ }
219
+ function detectDatabaseModules(packageJson) {
220
+ const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
221
+ const modules = [];
222
+ if (deps["@prisma/client"] || deps["prisma"]) {
223
+ modules.push("prisma");
224
+ }
225
+ if (deps["mongoose"]) {
226
+ modules.push("mongoose");
227
+ }
228
+ return modules;
229
+ }
230
+ async function checkKeyFiles(projectRoot, projectType, authModules, databaseModules) {
231
+ const checks = [];
232
+ // Check .env.example
233
+ const envExampleExists = await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, ".env.example"));
234
+ checks.push({
235
+ status: envExampleExists ? "success" : "warning",
236
+ message: envExampleExists ? ".env.example file found" : ".env.example file missing (recommended for documentation)",
237
+ });
238
+ // Check Prisma schema
239
+ if (databaseModules.includes("prisma")) {
240
+ const schemaExists = await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, "prisma", "schema.prisma"));
241
+ checks.push({
242
+ status: schemaExists ? "success" : "error",
243
+ message: schemaExists ? "Prisma schema found" : "Prisma schema missing (required for Prisma)",
244
+ });
245
+ }
246
+ // Check auth routes
247
+ if (authModules.length > 0 && projectType === "nextjs") {
248
+ const authRoutesExist = await checkAuthRoutesExist(projectRoot, projectType);
249
+ checks.push({
250
+ status: authRoutesExist ? "success" : "warning",
251
+ message: authRoutesExist ? "Auth routes configured" : "Auth routes not found (may need configuration)",
252
+ });
253
+ }
254
+ return checks;
255
+ }
256
+ async function checkAuthRoutesExist(projectRoot, projectType) {
257
+ if (projectType !== "nextjs")
258
+ return true; // Skip for non-Next.js
259
+ const possiblePaths = [
260
+ "app/api/auth/[...nextauth]/route.ts",
261
+ "app/api/auth/[...nextauth]/route.js",
262
+ "src/app/api/auth/[...nextauth]/route.ts",
263
+ "src/app/api/auth/[...nextauth]/route.js",
264
+ "pages/api/auth/[...nextauth].ts",
265
+ "pages/api/auth/[...nextauth].js",
266
+ "src/pages/api/auth/[...nextauth].ts",
267
+ "src/pages/api/auth/[...nextauth].js",
268
+ ];
269
+ for (const routePath of possiblePaths) {
270
+ if (await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, routePath))) {
271
+ return true;
272
+ }
273
+ }
274
+ return false;
275
+ }
276
+ async function checkEnvFiles(projectRoot, authModules, databaseModules) {
277
+ const checks = [];
278
+ const requiredKeys = [];
279
+ const missing = [];
280
+ const present = [];
281
+ // Determine required env keys
282
+ if (databaseModules.includes("prisma")) {
283
+ requiredKeys.push("DATABASE_URL");
284
+ }
285
+ if (authModules.includes("authjs")) {
286
+ requiredKeys.push("NEXTAUTH_SECRET", "NEXTAUTH_URL");
287
+ }
288
+ if (authModules.includes("better-auth")) {
289
+ requiredKeys.push("BETTER_AUTH_SECRET", "BETTER_AUTH_URL");
290
+ }
291
+ // Check env files
292
+ const envPaths = [".env", ".env.local"];
293
+ let envContent = "";
294
+ for (const envPath of envPaths) {
295
+ const fullPath = path_1.default.join(projectRoot, envPath);
296
+ if (await fs_extra_1.default.pathExists(fullPath)) {
297
+ envContent = await fs_extra_1.default.readFile(fullPath, "utf-8");
298
+ break;
299
+ }
300
+ }
301
+ if (!envContent) {
302
+ checks.push({
303
+ status: "warning",
304
+ message: "No .env or .env.local file found",
305
+ });
306
+ return { checks, envStatus: { missing: requiredKeys, present: [] } };
307
+ }
308
+ // Parse env content
309
+ const envLines = envContent.split("\n").map(line => line.trim()).filter(line => line && !line.startsWith("#"));
310
+ const envVars = new Set(envLines.map(line => line.split("=")[0]));
311
+ for (const key of requiredKeys) {
312
+ if (envVars.has(key)) {
313
+ present.push(key);
314
+ }
315
+ else {
316
+ missing.push(key);
317
+ }
318
+ }
319
+ if (missing.length > 0) {
320
+ checks.push({
321
+ status: "error",
322
+ message: `Missing required environment variables: ${missing.join(", ")}`,
323
+ });
324
+ }
325
+ else if (requiredKeys.length > 0) {
326
+ checks.push({
327
+ status: "success",
328
+ message: "All required environment variables are present",
329
+ });
330
+ }
331
+ return { checks, envStatus: { missing, present } };
332
+ }
333
+ function checkConflicts(authModules, databaseModules) {
334
+ const conflicts = [];
335
+ if (authModules.length > 1) {
336
+ conflicts.push(`Multiple auth providers detected: ${authModules.join(", ")}. Consider using only one.`);
337
+ }
338
+ if (databaseModules.length > 1) {
339
+ conflicts.push(`Multiple database providers detected: ${databaseModules.join(", ")}. Consider using only one.`);
340
+ }
341
+ return conflicts;
342
+ }
343
+ async function checkConfigFiles(projectRoot, projectType, packageJson) {
344
+ const checks = [];
345
+ // Check tsconfig.json
346
+ const tsconfigExists = await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, "tsconfig.json"));
347
+ checks.push({
348
+ status: tsconfigExists ? "success" : "error",
349
+ message: tsconfigExists ? MESSAGES.TSCONFIG_FOUND : MESSAGES.TSCONFIG_MISSING,
350
+ });
351
+ // Check ESLint config
352
+ const eslintExists = await checkEslintConfigExists(projectRoot);
353
+ checks.push({
354
+ status: eslintExists ? "success" : "warning",
355
+ message: eslintExists ? MESSAGES.ESLINT_CONFIG_FOUND : MESSAGES.ESLINT_CONFIG_MISSING,
356
+ });
357
+ // Check build script
358
+ const hasBuildScript = packageJson.scripts && typeof packageJson.scripts === "object" && "build" in packageJson.scripts;
359
+ checks.push({
360
+ status: hasBuildScript ? "success" : "warning",
361
+ message: hasBuildScript ? MESSAGES.BUILD_SCRIPT_FOUND : MESSAGES.BUILD_SCRIPT_MISSING,
362
+ });
363
+ return checks;
364
+ }
365
+ async function checkDependencies(packageJson) {
366
+ const outdated = [];
367
+ // Simple check: if dependencies have ^ or ~, assume up to date for now
368
+ // In production, integrate with npm outdated or similar
369
+ const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
370
+ for (const [name, version] of Object.entries(deps || {})) {
371
+ if (typeof version === "string" && (version.startsWith("^") || version.startsWith("~"))) {
372
+ // Assume up to date
373
+ }
374
+ else {
375
+ outdated.push(name);
376
+ }
377
+ }
378
+ return {
379
+ status: outdated.length > 0 ? "warning" : "success",
380
+ message: outdated.length > 0 ? MESSAGES.DEPENDENCY_OUTDATED(outdated) : MESSAGES.DEPENDENCY_UP_TO_DATE,
381
+ outdated,
382
+ };
383
+ }
384
+ async function checkGitRepo(projectRoot) {
385
+ const gitExists = await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, ".git"));
386
+ return {
387
+ status: gitExists ? "success" : "warning",
388
+ message: gitExists ? MESSAGES.GIT_REPO_FOUND : MESSAGES.GIT_REPO_MISSING,
389
+ };
390
+ }
391
+ async function checkEslintConfigExists(projectRoot) {
392
+ const possibleConfigs = [
393
+ ".eslintrc.js",
394
+ ".eslintrc.json",
395
+ ".eslintrc.yml",
396
+ ".eslintrc.yaml",
397
+ "eslint.config.js",
398
+ "eslint.config.mjs",
399
+ ];
400
+ for (const config of possibleConfigs) {
401
+ if (await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, config))) {
402
+ return true;
403
+ }
404
+ }
405
+ return false;
406
+ }
407
+ function generateSuggestions() {
408
+ const suggestions = [];
409
+ // Always show available commands
410
+ suggestions.push("stackkit add auth - Add authentication module");
411
+ suggestions.push("stackkit add db - Add database module");
412
+ suggestions.push("stackkit list - View available modules");
413
+ return suggestions;
414
+ }
415
+ function printDoctorReport(report, verbose) {
416
+ logger_1.logger.header("🔍 StackKit Doctor Report");
417
+ logger_1.logger.newLine();
418
+ // Project info
419
+ logger_1.logger.log(chalk_1.default.bold("Project"));
420
+ logger_1.logger.log(` Type: ${report.project.type}`);
421
+ logger_1.logger.log(` Root: ${report.project.root}`);
422
+ logger_1.logger.log(` Package Manager: ${report.project.packageManager}`);
423
+ logger_1.logger.newLine();
424
+ // Runtime
425
+ logger_1.logger.log(chalk_1.default.bold("Runtime"));
426
+ if (report.runtime.nodeVersionStatus === "success") {
427
+ logger_1.logger.success(`Node.js: ${report.runtime.nodeVersion}`);
428
+ }
429
+ else if (report.runtime.nodeVersionStatus === "warning") {
430
+ logger_1.logger.warn(`Node.js: ${report.runtime.nodeVersion}`);
431
+ }
432
+ else {
433
+ logger_1.logger.error(`Node.js: ${report.runtime.nodeVersion}`);
434
+ }
435
+ logger_1.logger.newLine();
436
+ // Modules
437
+ logger_1.logger.log(chalk_1.default.bold("Modules"));
438
+ if (report.modules.auth.length > 0) {
439
+ logger_1.logger.log(` Auth: ${report.modules.auth.join(", ")}`);
440
+ }
441
+ else {
442
+ logger_1.logger.info("Auth: None");
443
+ }
444
+ if (report.modules.database.length > 0) {
445
+ logger_1.logger.log(` Database: ${report.modules.database.join(", ")}`);
446
+ }
447
+ else {
448
+ logger_1.logger.info("Database: None");
449
+ }
450
+ logger_1.logger.newLine();
451
+ // Files
452
+ logger_1.logger.log(chalk_1.default.bold("Files"));
453
+ if (report.files.envExample) {
454
+ logger_1.logger.success(MESSAGES.ENV_EXAMPLE_FOUND);
455
+ }
456
+ else {
457
+ logger_1.logger.warn(MESSAGES.ENV_EXAMPLE_MISSING);
458
+ logger_1.logger.log(" Hint: Helps other developers understand required environment variables");
459
+ }
460
+ if (report.files.env) {
461
+ logger_1.logger.success(MESSAGES.ENV_FOUND);
462
+ }
463
+ else {
464
+ logger_1.logger.warn(MESSAGES.ENV_MISSING);
465
+ logger_1.logger.log(" Hint: Required for local development and production deployment");
466
+ }
467
+ if (report.files.prismaSchema !== undefined) {
468
+ if (report.files.prismaSchema) {
469
+ logger_1.logger.success(MESSAGES.PRISMA_SCHEMA_FOUND);
470
+ }
471
+ else {
472
+ logger_1.logger.error(MESSAGES.PRISMA_SCHEMA_MISSING);
473
+ logger_1.logger.log(" Hint: Defines your database schema and is required for Prisma to work");
474
+ }
475
+ }
476
+ if (report.files.authRoutes !== undefined) {
477
+ if (report.files.authRoutes) {
478
+ logger_1.logger.success(MESSAGES.AUTH_ROUTES_FOUND);
479
+ }
480
+ else {
481
+ logger_1.logger.warn(MESSAGES.AUTH_ROUTES_MISSING);
482
+ logger_1.logger.log(" Hint: Authentication routes handle login/logout flows");
483
+ }
484
+ }
485
+ if (report.files.tsconfig !== undefined) {
486
+ if (report.files.tsconfig) {
487
+ logger_1.logger.success(MESSAGES.TSCONFIG_FOUND);
488
+ }
489
+ else {
490
+ logger_1.logger.error(MESSAGES.TSCONFIG_MISSING);
491
+ logger_1.logger.log(" Hint: Required for TypeScript compilation");
492
+ }
493
+ }
494
+ if (report.files.eslintConfig !== undefined) {
495
+ if (report.files.eslintConfig) {
496
+ logger_1.logger.success(MESSAGES.ESLINT_CONFIG_FOUND);
497
+ }
498
+ else {
499
+ logger_1.logger.warn(MESSAGES.ESLINT_CONFIG_MISSING);
500
+ logger_1.logger.log(" Hint: Helps maintain code quality");
501
+ }
502
+ }
503
+ if (report.files.git !== undefined) {
504
+ if (report.files.git) {
505
+ logger_1.logger.success(MESSAGES.GIT_REPO_FOUND);
506
+ }
507
+ else {
508
+ logger_1.logger.warn(MESSAGES.GIT_REPO_MISSING);
509
+ logger_1.logger.log(" Hint: Recommended for version control");
510
+ }
511
+ }
512
+ logger_1.logger.newLine();
513
+ // Dependencies
514
+ if (report.dependencies.outdated.length > 0) {
515
+ logger_1.logger.log(chalk_1.default.bold("Dependencies"));
516
+ logger_1.logger.warn(MESSAGES.DEPENDENCY_OUTDATED(report.dependencies.outdated));
517
+ logger_1.logger.log(" Hint: Run package manager update command");
518
+ logger_1.logger.newLine();
519
+ }
520
+ // Environment
521
+ if (report.env.missing.length > 0 || report.env.present.length > 0) {
522
+ logger_1.logger.log(chalk_1.default.bold("Environment Variables"));
523
+ if (report.env.present.length > 0) {
524
+ logger_1.logger.success(MESSAGES.ENV_VARS_PRESENT(report.env.present));
525
+ }
526
+ if (report.env.missing.length > 0) {
527
+ logger_1.logger.error(MESSAGES.ENV_VARS_MISSING(report.env.missing));
528
+ }
529
+ logger_1.logger.newLine();
530
+ }
531
+ // Conflicts
532
+ if (report.conflicts.length > 0) {
533
+ logger_1.logger.log(chalk_1.default.bold("Conflicts"));
534
+ report.conflicts.forEach(conflict => {
535
+ logger_1.logger.warn(conflict);
536
+ });
537
+ logger_1.logger.newLine();
538
+ }
539
+ // Detailed checks if verbose
540
+ if (verbose) {
541
+ logger_1.logger.log(chalk_1.default.bold("Detailed Checks"));
542
+ report.checks.forEach(check => {
543
+ if (check.status === "success") {
544
+ logger_1.logger.success(check.message);
545
+ }
546
+ else if (check.status === "warning") {
547
+ logger_1.logger.warn(check.message);
548
+ }
549
+ else {
550
+ logger_1.logger.error(check.message);
551
+ }
552
+ if (check.details) {
553
+ logger_1.logger.log(` ${chalk_1.default.gray(check.details)}`);
554
+ }
555
+ });
556
+ logger_1.logger.newLine();
557
+ }
558
+ // Summary
559
+ logger_1.logger.log(chalk_1.default.bold("Summary"));
560
+ logger_1.logger.log(` Errors: ${report.summary.errors}`);
561
+ logger_1.logger.log(` Warnings: ${report.summary.warnings}`);
562
+ logger_1.logger.newLine();
563
+ if (report.summary.suggestions.length > 0) {
564
+ logger_1.logger.log(chalk_1.default.bold("Suggestions"));
565
+ report.summary.suggestions.forEach(suggestion => {
566
+ logger_1.logger.log(` • ${suggestion}`);
567
+ });
568
+ }
569
+ }
@@ -0,0 +1,6 @@
1
+ interface ListOptions {
2
+ frameworks?: boolean;
3
+ modules?: boolean;
4
+ }
5
+ export declare function listCommand(options: ListOptions): Promise<void>;
6
+ export {};