stackkit-cli 0.4.2 → 0.4.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.
Files changed (133) hide show
  1. package/README.md +17 -10
  2. package/bin/stackkit.js +1 -1
  3. package/dist/commands/add.js +26 -24
  4. package/dist/commands/init.d.ts +1 -1
  5. package/dist/commands/init.js +34 -29
  6. package/dist/commands/list.js +12 -12
  7. package/dist/index.js +25 -23
  8. package/dist/types/index.d.ts +14 -14
  9. package/dist/utils/code-inject.d.ts +1 -1
  10. package/dist/utils/code-inject.js +6 -6
  11. package/dist/utils/detect.d.ts +1 -1
  12. package/dist/utils/detect.js +48 -44
  13. package/dist/utils/env-editor.js +20 -20
  14. package/dist/utils/files.js +4 -4
  15. package/dist/utils/json-editor.d.ts +3 -3
  16. package/dist/utils/json-editor.js +10 -14
  17. package/dist/utils/logger.d.ts +1 -1
  18. package/dist/utils/logger.js +8 -8
  19. package/dist/utils/package-manager.d.ts +2 -2
  20. package/dist/utils/package-manager.js +33 -26
  21. package/modules/auth/better-auth-express/adapters/mongoose-mongodb.ts +13 -0
  22. package/modules/auth/better-auth-express/adapters/prisma-mongodb.ts +15 -0
  23. package/modules/auth/better-auth-express/adapters/prisma-postgresql.ts +15 -0
  24. package/modules/auth/better-auth-express/files/lib/auth.ts +1 -1
  25. package/modules/auth/better-auth-express/files/routes/auth.ts +3 -3
  26. package/modules/auth/better-auth-express/files/schemas/prisma-mongodb-schema.prisma +72 -0
  27. package/modules/auth/better-auth-express/files/schemas/prisma-postgresql-schema.prisma +72 -0
  28. package/modules/auth/better-auth-express/module.json +26 -3
  29. package/modules/auth/better-auth-nextjs/adapters/mongoose-mongodb.ts +24 -0
  30. package/modules/auth/better-auth-nextjs/adapters/prisma-mongodb.ts +26 -0
  31. package/modules/auth/better-auth-nextjs/adapters/prisma-postgresql.ts +26 -0
  32. package/modules/auth/better-auth-nextjs/files/api/auth/[...all]/route.ts +2 -3
  33. package/modules/auth/better-auth-nextjs/files/lib/auth.ts +4 -4
  34. package/modules/auth/better-auth-nextjs/files/schemas/prisma-mongodb-schema.prisma +72 -0
  35. package/modules/auth/better-auth-nextjs/files/schemas/prisma-postgresql-schema.prisma +72 -0
  36. package/modules/auth/better-auth-nextjs/module.json +26 -5
  37. package/modules/auth/better-auth-react/files/lib/auth-client.ts +2 -2
  38. package/modules/auth/better-auth-react/module.json +7 -5
  39. package/modules/auth/clerk-express/files/lib/auth.ts +1 -1
  40. package/modules/auth/clerk-express/module.json +22 -8
  41. package/modules/auth/clerk-nextjs/files/lib/auth-provider.tsx +1 -1
  42. package/modules/auth/clerk-nextjs/files/middleware.ts +3 -3
  43. package/modules/auth/clerk-nextjs/module.json +50 -14
  44. package/modules/auth/clerk-react/files/lib/auth-provider.tsx +2 -2
  45. package/modules/auth/clerk-react/module.json +16 -7
  46. package/modules/database/mongoose-mongodb/files/lib/db.ts +3 -3
  47. package/modules/database/mongoose-mongodb/module.json +43 -6
  48. package/modules/database/prisma-mongodb/files/lib/db.ts +2 -2
  49. package/modules/database/prisma-mongodb/files/prisma/schema.prisma +1 -1
  50. package/modules/database/prisma-mongodb/module.json +28 -4
  51. package/modules/database/prisma-postgresql/files/lib/db.ts +2 -2
  52. package/modules/database/prisma-postgresql/files/prisma/schema.prisma +1 -1
  53. package/modules/database/prisma-postgresql/module.json +28 -4
  54. package/package.json +1 -1
  55. package/templates/express/.env.example +11 -0
  56. package/templates/express/eslint.config.cjs +42 -0
  57. package/templates/express/package.json +39 -0
  58. package/templates/express/src/app.ts +71 -0
  59. package/templates/express/src/config/env.ts +23 -0
  60. package/templates/express/src/middlewares/error.middleware.ts +18 -0
  61. package/templates/{bases/express-base → express}/src/server.ts +2 -2
  62. package/templates/express/template.json +44 -0
  63. package/templates/express/tsconfig.json +31 -0
  64. package/templates/{bases/nextjs-base → nextjs}/app/layout.tsx +1 -5
  65. package/templates/nextjs/app/page.tsx +57 -0
  66. package/templates/{bases/nextjs-base → nextjs}/package.json +2 -1
  67. package/templates/{bases/nextjs-base → nextjs}/template.json +13 -1
  68. package/templates/react-vite/.env.example +2 -0
  69. package/templates/react-vite/README.md +85 -0
  70. package/templates/react-vite/eslint.config.js +23 -0
  71. package/templates/{bases/react-vite-base → react-vite}/index.html +1 -0
  72. package/templates/{bases/react-vite-base → react-vite}/package.json +16 -2
  73. package/templates/react-vite/src/api/client.ts +47 -0
  74. package/templates/react-vite/src/api/services/user.service.ts +18 -0
  75. package/templates/react-vite/src/components/ErrorBoundary.tsx +51 -0
  76. package/templates/react-vite/src/components/Layout.tsx +13 -0
  77. package/templates/react-vite/src/components/Loading.tsx +8 -0
  78. package/templates/react-vite/src/components/SEO.tsx +49 -0
  79. package/templates/react-vite/src/config/constants.ts +5 -0
  80. package/templates/react-vite/src/hooks/index.ts +64 -0
  81. package/templates/react-vite/src/index.css +1 -0
  82. package/templates/react-vite/src/lib/queryClient.ts +12 -0
  83. package/templates/react-vite/src/main.tsx +22 -0
  84. package/templates/react-vite/src/pages/About.tsx +78 -0
  85. package/templates/react-vite/src/pages/Home.tsx +49 -0
  86. package/templates/react-vite/src/pages/NotFound.tsx +24 -0
  87. package/templates/react-vite/src/pages/UserProfile.tsx +40 -0
  88. package/templates/react-vite/src/router.tsx +33 -0
  89. package/templates/react-vite/src/types/api.d.ts +20 -0
  90. package/templates/react-vite/src/types/user.d.ts +6 -0
  91. package/templates/react-vite/src/utils/helpers.ts +51 -0
  92. package/templates/react-vite/src/utils/storage.ts +35 -0
  93. package/templates/react-vite/src/vite-env.d.ts +11 -0
  94. package/templates/react-vite/template.json +46 -0
  95. package/templates/react-vite/tsconfig.json +4 -0
  96. package/templates/react-vite/vite.config.ts +13 -0
  97. package/modules/database/drizzle-postgresql/files/drizzle.config.ts +0 -10
  98. package/modules/database/drizzle-postgresql/files/lib/db.ts +0 -7
  99. package/modules/database/drizzle-postgresql/files/lib/schema.ts +0 -8
  100. package/modules/database/drizzle-postgresql/module.json +0 -35
  101. package/templates/bases/express-base/.env.example +0 -2
  102. package/templates/bases/express-base/package.json +0 -23
  103. package/templates/bases/express-base/src/app.ts +0 -34
  104. package/templates/bases/express-base/src/config/env.ts +0 -14
  105. package/templates/bases/express-base/src/middlewares/error.middleware.ts +0 -12
  106. package/templates/bases/express-base/template.json +0 -7
  107. package/templates/bases/express-base/tsconfig.json +0 -14
  108. package/templates/bases/nextjs-base/app/page.tsx +0 -65
  109. package/templates/bases/react-vite-base/README.md +0 -73
  110. package/templates/bases/react-vite-base/eslint.config.js +0 -23
  111. package/templates/bases/react-vite-base/src/App.css +0 -42
  112. package/templates/bases/react-vite-base/src/App.tsx +0 -35
  113. package/templates/bases/react-vite-base/src/index.css +0 -68
  114. package/templates/bases/react-vite-base/src/main.tsx +0 -10
  115. package/templates/bases/react-vite-base/template.json +0 -19
  116. package/templates/bases/react-vite-base/tsconfig.json +0 -7
  117. package/templates/bases/react-vite-base/vite.config.ts +0 -7
  118. /package/templates/{bases/nextjs-base → nextjs}/README.md +0 -0
  119. /package/templates/{bases/nextjs-base → nextjs}/app/favicon.ico +0 -0
  120. /package/templates/{bases/nextjs-base → nextjs}/app/globals.css +0 -0
  121. /package/templates/{bases/nextjs-base → nextjs}/eslint.config.mjs +0 -0
  122. /package/templates/{bases/nextjs-base → nextjs}/next.config.ts +0 -0
  123. /package/templates/{bases/nextjs-base → nextjs}/postcss.config.mjs +0 -0
  124. /package/templates/{bases/nextjs-base → nextjs}/public/file.svg +0 -0
  125. /package/templates/{bases/nextjs-base → nextjs}/public/globe.svg +0 -0
  126. /package/templates/{bases/nextjs-base → nextjs}/public/next.svg +0 -0
  127. /package/templates/{bases/nextjs-base → nextjs}/public/vercel.svg +0 -0
  128. /package/templates/{bases/nextjs-base → nextjs}/public/window.svg +0 -0
  129. /package/templates/{bases/nextjs-base → nextjs}/tsconfig.json +0 -0
  130. /package/templates/{bases/react-vite-base → react-vite}/public/vite.svg +0 -0
  131. /package/templates/{bases/react-vite-base → react-vite}/src/assets/react.svg +0 -0
  132. /package/templates/{bases/react-vite-base → react-vite}/tsconfig.app.json +0 -0
  133. /package/templates/{bases/react-vite-base → react-vite}/tsconfig.node.json +0 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # stackkit-cli
2
2
 
3
- Add modules to existing projects.
3
+ Add authentication and database modules to existing projects.
4
4
 
5
5
  ## Usage
6
6
 
@@ -15,18 +15,25 @@ npx stackkit-cli add database
15
15
  npx stackkit-cli list
16
16
  ```
17
17
 
18
- ## Available Commands
18
+ ## Features
19
19
 
20
- ### `add <module>`
21
- Add authentication or database module to your project. Interactive wizard guides you through options.
20
+ - **Auto-detects** your framework (Next.js, Express, React)
21
+ - **Shows compatible modules** for your project
22
+ - **Installs dependencies** automatically
23
+ - **Configures everything** - files, env vars, and setup
22
24
 
23
- ### `list`
24
- List all available modules.
25
+ ## Available Modules
25
26
 
26
- ## Documentation
27
+ ### Authentication
28
+
29
+ - Better Auth (Next.js, Express, React)
30
+ - Clerk (Next.js, Express, React)
27
31
 
28
- See [main repository](https://github.com/tariqul420/stackkit) for full documentation.
32
+ ### Database
29
33
 
30
- ## License
34
+ - Prisma with PostgreSQL or MongoDB (Next.js, Express)
35
+ - Mongoose with MongoDB (Next.js, Express)
36
+
37
+ ## Documentation
31
38
 
32
- MIT
39
+ Full documentation: [stackkit.dev](https://stackkit.dev) | [GitHub](https://github.com/tariqul420/stackkit)
package/bin/stackkit.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- require('../dist/index.js');
2
+ require("../dist/index.js");
@@ -17,11 +17,11 @@ async function addCommand(module, options) {
17
17
  try {
18
18
  const projectRoot = process.cwd();
19
19
  // Detect project info
20
- const spinner = logger_1.logger.startSpinner('Detecting project...');
20
+ const spinner = logger_1.logger.startSpinner("Detecting project...");
21
21
  const projectInfo = await (0, detect_1.detectProjectInfo)(projectRoot);
22
22
  spinner.succeed(`Detected ${projectInfo.framework} (${projectInfo.router} router, ${projectInfo.language})`);
23
23
  // Load module metadata
24
- const modulesDir = path_1.default.join(__dirname, '..', '..', 'modules');
24
+ const modulesDir = path_1.default.join(__dirname, "..", "..", "modules");
25
25
  const moduleMetadata = await loadModuleMetadata(modulesDir, module, options.provider);
26
26
  if (!moduleMetadata) {
27
27
  logger_1.logger.error(`Module "${module}" not found`);
@@ -29,27 +29,27 @@ async function addCommand(module, options) {
29
29
  }
30
30
  // Check if framework is supported
31
31
  if (!moduleMetadata.supportedFrameworks.includes(projectInfo.framework)) {
32
- logger_1.logger.error(`Module "${module}" does not support ${projectInfo.framework}. Supported: ${moduleMetadata.supportedFrameworks.join(', ')}`);
32
+ logger_1.logger.error(`Module "${module}" does not support ${projectInfo.framework}. Supported: ${moduleMetadata.supportedFrameworks.join(", ")}`);
33
33
  process.exit(1);
34
34
  }
35
35
  // Check for conflicts
36
- if (module === 'auth' && projectInfo.hasAuth && !options.force) {
37
- logger_1.logger.warn('Auth library already detected in this project');
36
+ if (module === "auth" && projectInfo.hasAuth && !options.force) {
37
+ logger_1.logger.warn("Auth library already detected in this project");
38
38
  const { proceed } = await inquirer_1.default.prompt([
39
39
  {
40
- type: 'confirm',
41
- name: 'proceed',
42
- message: 'Continue anyway? (use --force to skip this prompt)',
40
+ type: "confirm",
41
+ name: "proceed",
42
+ message: "Continue anyway? (use --force to skip this prompt)",
43
43
  default: false,
44
44
  },
45
45
  ]);
46
46
  if (!proceed) {
47
- logger_1.logger.info('Cancelled');
47
+ logger_1.logger.info("Cancelled");
48
48
  process.exit(0);
49
49
  }
50
50
  }
51
51
  if (options.dryRun) {
52
- logger_1.logger.warn('Dry run mode - no changes will be made');
52
+ logger_1.logger.warn("Dry run mode - no changes will be made");
53
53
  logger_1.logger.newLine();
54
54
  }
55
55
  // Apply module patches
@@ -61,7 +61,7 @@ async function addCommand(module, options) {
61
61
  await (0, package_manager_1.addDependencies)(projectRoot, projectInfo.packageManager, deps, false);
62
62
  }
63
63
  else {
64
- logger_1.logger.info(`Would add dependencies: ${deps.join(', ')}`);
64
+ logger_1.logger.info(`Would add dependencies: ${deps.join(", ")}`);
65
65
  }
66
66
  }
67
67
  // Add dev dependencies
@@ -73,7 +73,7 @@ async function addCommand(module, options) {
73
73
  await (0, package_manager_1.addDependencies)(projectRoot, projectInfo.packageManager, devDeps, true);
74
74
  }
75
75
  else {
76
- logger_1.logger.info(`Would add dev dependencies: ${devDeps.join(', ')}`);
76
+ logger_1.logger.info(`Would add dev dependencies: ${devDeps.join(", ")}`);
77
77
  }
78
78
  }
79
79
  // Add environment variables
@@ -82,7 +82,7 @@ async function addCommand(module, options) {
82
82
  await (0, env_editor_1.addEnvVariables)(projectRoot, moduleMetadata.envVars, { force: options.force });
83
83
  }
84
84
  else {
85
- logger_1.logger.log(` ${chalk_1.default.dim('~')} .env.example`);
85
+ logger_1.logger.log(` ${chalk_1.default.dim("~")} .env.example`);
86
86
  }
87
87
  }
88
88
  logger_1.logger.newLine();
@@ -90,7 +90,7 @@ async function addCommand(module, options) {
90
90
  logger_1.logger.newLine();
91
91
  // Print next steps
92
92
  if (moduleMetadata.envVars.some((v) => v.required)) {
93
- logger_1.logger.log('Next: Fill in environment variables in .env');
93
+ logger_1.logger.log("Next: Fill in environment variables in .env");
94
94
  }
95
95
  logger_1.logger.newLine();
96
96
  }
@@ -120,7 +120,7 @@ async function loadModuleMetadata(modulesDir, moduleName, provider) {
120
120
  const moduleStat = await fs_extra_1.default.stat(modulePath);
121
121
  if (!moduleStat.isDirectory())
122
122
  continue;
123
- const metadataPath = path_1.default.join(modulePath, 'module.json');
123
+ const metadataPath = path_1.default.join(modulePath, "module.json");
124
124
  if (await fs_extra_1.default.pathExists(metadataPath)) {
125
125
  const metadata = await fs_extra_1.default.readJSON(metadataPath);
126
126
  // If provider is specified, match by directory name (exact match)
@@ -136,13 +136,15 @@ async function loadModuleMetadata(modulesDir, moduleName, provider) {
136
136
  }
137
137
  return null;
138
138
  }
139
+ // (removed duplicate import)
139
140
  async function applyModulePatches(projectRoot, projectInfo, moduleMetadata, modulesDir, moduleName, options) {
141
+ // Find the module path
140
142
  const moduleBasePath = await findModulePath(modulesDir, moduleName, options.provider);
141
143
  if (!moduleBasePath) {
142
- throw new Error('Module files not found');
144
+ throw new Error("Module files not found");
143
145
  }
144
146
  for (const patch of moduleMetadata.patches) {
145
- if (patch.type === 'create-file') {
147
+ if (patch.type === "create-file") {
146
148
  const filePatch = patch;
147
149
  // Check conditions
148
150
  if (filePatch.condition) {
@@ -153,18 +155,18 @@ async function applyModulePatches(projectRoot, projectInfo, moduleMetadata, modu
153
155
  continue; // Skip this patch
154
156
  }
155
157
  }
156
- const sourceFile = path_1.default.join(moduleBasePath, 'files', filePatch.source);
158
+ const sourceFile = path_1.default.join(moduleBasePath, "files", filePatch.source);
157
159
  let destFile = path_1.default.join(projectRoot, filePatch.destination);
158
160
  // Replace placeholders in destination
159
161
  destFile = destFile
160
- .replace('{{router}}', (0, detect_1.getRouterBasePath)(projectInfo))
161
- .replace('{{lib}}', (0, detect_1.getLibPath)(projectInfo));
162
+ .replace("{{router}}", (0, detect_1.getRouterBasePath)(projectInfo))
163
+ .replace("{{lib}}", (0, detect_1.getLibPath)(projectInfo));
162
164
  if (!options.dryRun) {
163
165
  if (await (0, files_1.fileExists)(sourceFile)) {
164
- const content = await fs_extra_1.default.readFile(sourceFile, 'utf-8');
166
+ const content = await fs_extra_1.default.readFile(sourceFile, "utf-8");
165
167
  await (0, files_1.createFile)(destFile, content, { force: options.force });
166
168
  const relativePath = path_1.default.relative(projectRoot, destFile);
167
- logger_1.logger.log(` ${chalk_1.default.green('+')} ${relativePath}`);
169
+ logger_1.logger.log(` ${chalk_1.default.green("+")} ${relativePath}`);
168
170
  }
169
171
  else {
170
172
  logger_1.logger.warn(`Source file not found: ${filePatch.source}`);
@@ -172,7 +174,7 @@ async function applyModulePatches(projectRoot, projectInfo, moduleMetadata, modu
172
174
  }
173
175
  else {
174
176
  const relativePath = path_1.default.relative(projectRoot, destFile);
175
- logger_1.logger.log(` ${chalk_1.default.dim('+')} ${relativePath}`);
177
+ logger_1.logger.log(` ${chalk_1.default.dim("+")} ${relativePath}`);
176
178
  }
177
179
  }
178
180
  }
@@ -190,7 +192,7 @@ async function findModulePath(modulesDir, moduleName, provider) {
190
192
  const moduleStat = await fs_extra_1.default.stat(modulePath);
191
193
  if (!moduleStat.isDirectory())
192
194
  continue;
193
- const metadataPath = path_1.default.join(modulePath, 'module.json');
195
+ const metadataPath = path_1.default.join(modulePath, "module.json");
194
196
  if (await fs_extra_1.default.pathExists(metadataPath)) {
195
197
  const metadata = await fs_extra_1.default.readJSON(metadataPath);
196
198
  // If provider is specified, match by directory name (exact match)
@@ -1,4 +1,4 @@
1
- import { PackageManager } from '../utils/package-manager';
1
+ import { PackageManager } from "../utils/package-manager";
2
2
  interface InitOptions {
3
3
  template?: string;
4
4
  pm?: PackageManager;
@@ -15,24 +15,24 @@ const package_manager_1 = require("../utils/package-manager");
15
15
  async function initCommand(projectName, options) {
16
16
  try {
17
17
  // Validate package manager option
18
- if (options.pm && !['npm', 'yarn', 'pnpm'].includes(options.pm)) {
19
- logger_1.logger.error(`Invalid package manager: ${options.pm}. Use npm, yarn, or pnpm.`);
18
+ if (options.pm && !["npm", "yarn", "pnpm", "bun"].includes(options.pm)) {
19
+ logger_1.logger.error(`Invalid package manager: ${options.pm}. Use npm, yarn, pnpm, or bun.`);
20
20
  process.exit(1);
21
21
  }
22
22
  // Get available templates
23
- const templatesDir = path_1.default.join(__dirname, '..', '..', 'templates');
23
+ const templatesDir = path_1.default.join(__dirname, "..", "..", "templates");
24
24
  const templates = await getAvailableTemplates(templatesDir);
25
25
  if (templates.length === 0) {
26
- logger_1.logger.error('No templates found');
26
+ logger_1.logger.error("No templates found");
27
27
  process.exit(1);
28
28
  }
29
29
  // Prompt for project details if not using --yes
30
30
  let answers;
31
31
  if (options.yes) {
32
32
  answers = {
33
- projectName: projectName || 'my-app',
33
+ projectName: projectName || "my-app",
34
34
  template: options.template || templates[0].name,
35
- packageManager: options.pm || 'pnpm',
35
+ packageManager: options.pm || "pnpm",
36
36
  install: options.install !== false,
37
37
  git: options.git !== false,
38
38
  };
@@ -40,23 +40,23 @@ async function initCommand(projectName, options) {
40
40
  else {
41
41
  const prompted = await inquirer_1.default.prompt([
42
42
  {
43
- type: 'input',
44
- name: 'projectName',
45
- message: 'Project name:',
46
- default: projectName || 'my-app',
43
+ type: "input",
44
+ name: "projectName",
45
+ message: "Project name:",
46
+ default: projectName || "my-app",
47
47
  when: !projectName,
48
48
  validate: (input) => {
49
49
  const validation = (0, validate_npm_package_name_1.default)(input);
50
50
  if (!validation.validForNewPackages) {
51
- return validation.errors?.[0] || 'Invalid package name';
51
+ return validation.errors?.[0] || "Invalid package name";
52
52
  }
53
53
  return true;
54
54
  },
55
55
  },
56
56
  {
57
- type: 'list',
58
- name: 'template',
59
- message: 'Select a template:',
57
+ type: "list",
58
+ name: "template",
59
+ message: "Select a template:",
60
60
  choices: templates.map((t) => ({
61
61
  name: t.displayName,
62
62
  value: t.name,
@@ -64,24 +64,29 @@ async function initCommand(projectName, options) {
64
64
  when: !options.template,
65
65
  },
66
66
  {
67
- type: 'list',
68
- name: 'packageManager',
69
- message: 'Select a package manager:',
70
- choices: ['pnpm', 'npm', 'yarn'],
71
- default: 'pnpm',
67
+ type: "list",
68
+ name: "packageManager",
69
+ message: "Select a package manager:",
70
+ choices: [
71
+ { name: "pnpm (recommended)", value: "pnpm" },
72
+ { name: "npm", value: "npm" },
73
+ { name: "yarn", value: "yarn" },
74
+ { name: "bun", value: "bun" },
75
+ ],
76
+ default: "pnpm",
72
77
  when: !options.pm,
73
78
  },
74
79
  {
75
- type: 'confirm',
76
- name: 'install',
77
- message: 'Install dependencies?',
80
+ type: "confirm",
81
+ name: "install",
82
+ message: "Install dependencies?",
78
83
  default: true,
79
84
  when: options.install !== false,
80
85
  },
81
86
  {
82
- type: 'confirm',
83
- name: 'git',
84
- message: 'Initialize git repository?',
87
+ type: "confirm",
88
+ name: "git",
89
+ message: "Initialize git repository?",
85
90
  default: true,
86
91
  when: options.git !== false,
87
92
  },
@@ -98,7 +103,7 @@ async function initCommand(projectName, options) {
98
103
  // Check if directory exists
99
104
  if (await fs_extra_1.default.pathExists(targetDir)) {
100
105
  logger_1.logger.error(`Directory "${answers.projectName}" already exists`);
101
- logger_1.logger.info('Please choose a different name or remove the existing directory.');
106
+ logger_1.logger.info("Please choose a different name or remove the existing directory.");
102
107
  process.exit(1);
103
108
  }
104
109
  // Validate template exists
@@ -123,11 +128,11 @@ async function initCommand(projectName, options) {
123
128
  logger_1.logger.success(`Created ${chalk_1.default.bold(answers.projectName)}`);
124
129
  logger_1.logger.newLine();
125
130
  logger_1.logger.log(`Next steps:`);
126
- logger_1.logger.log(` ${chalk_1.default.cyan('cd')} ${answers.projectName}`);
131
+ logger_1.logger.log(` ${chalk_1.default.cyan("cd")} ${answers.projectName}`);
127
132
  if (!answers.install) {
128
133
  logger_1.logger.log(` ${chalk_1.default.cyan(answers.packageManager)} install`);
129
134
  }
130
- logger_1.logger.log(` ${chalk_1.default.cyan(answers.packageManager)} ${answers.packageManager === 'npm' ? 'run ' : ''}dev`);
135
+ logger_1.logger.log(` ${chalk_1.default.cyan(answers.packageManager)} ${answers.packageManager === "npm" ? "run " : ""}dev`);
131
136
  logger_1.logger.newLine();
132
137
  }
133
138
  catch (error) {
@@ -142,7 +147,7 @@ async function getAvailableTemplates(templatesDir) {
142
147
  const templateDirs = await fs_extra_1.default.readdir(templatesDir);
143
148
  const templates = [];
144
149
  for (const dir of templateDirs) {
145
- const metadataPath = path_1.default.join(templatesDir, dir, 'template.json');
150
+ const metadataPath = path_1.default.join(templatesDir, dir, "template.json");
146
151
  if (await fs_extra_1.default.pathExists(metadataPath)) {
147
152
  const metadata = await fs_extra_1.default.readJSON(metadataPath);
148
153
  templates.push(metadata);
@@ -15,28 +15,28 @@ async function listCommand(options) {
15
15
  logger_1.logger.newLine();
16
16
  // List templates
17
17
  if (showTemplates) {
18
- const templatesDir = path_1.default.join(__dirname, '..', '..', 'templates', 'bases');
18
+ const templatesDir = path_1.default.join(__dirname, "..", "..", "templates");
19
19
  const templates = await getAvailableTemplates(templatesDir);
20
- logger_1.logger.log(chalk_1.default.bold.cyan('▸ TEMPLATES') + chalk_1.default.gray(` (${templates.length})`));
20
+ logger_1.logger.log(chalk_1.default.bold.cyan("▸ TEMPLATES") + chalk_1.default.gray(` (${templates.length})`));
21
21
  logger_1.logger.newLine();
22
22
  if (templates.length === 0) {
23
- logger_1.logger.log(chalk_1.default.dim(' No templates available'));
23
+ logger_1.logger.log(chalk_1.default.dim(" No templates available"));
24
24
  }
25
25
  else {
26
- templates.forEach((template, index) => {
27
- logger_1.logger.log(` ${chalk_1.default.cyan('')} ${template.displayName}`);
26
+ templates.forEach((template) => {
27
+ logger_1.logger.log(` ${chalk_1.default.cyan("")} ${template.displayName}`);
28
28
  });
29
29
  }
30
30
  logger_1.logger.newLine();
31
31
  }
32
32
  // List modules
33
33
  if (showModules) {
34
- const modulesDir = path_1.default.join(__dirname, '..', '..', 'modules');
34
+ const modulesDir = path_1.default.join(__dirname, "..", "..", "modules");
35
35
  const modules = await getAvailableModules(modulesDir);
36
- logger_1.logger.log(chalk_1.default.bold.cyan('▸ MODULES') + chalk_1.default.gray(` (${modules.length})`));
36
+ logger_1.logger.log(chalk_1.default.bold.cyan("▸ MODULES") + chalk_1.default.gray(` (${modules.length})`));
37
37
  if (modules.length === 0) {
38
38
  logger_1.logger.newLine();
39
- logger_1.logger.log(chalk_1.default.dim(' No modules available'));
39
+ logger_1.logger.log(chalk_1.default.dim(" No modules available"));
40
40
  logger_1.logger.newLine();
41
41
  }
42
42
  else {
@@ -50,9 +50,9 @@ async function listCommand(options) {
50
50
  }, {});
51
51
  for (const [category, mods] of Object.entries(grouped)) {
52
52
  logger_1.logger.newLine();
53
- logger_1.logger.log(` ${chalk_1.default.yellow('')} ${chalk_1.default.bold.yellow(category.toUpperCase())} ${chalk_1.default.dim(`(${mods.length})`)}`);
53
+ logger_1.logger.log(` ${chalk_1.default.yellow("")} ${chalk_1.default.bold.yellow(category.toUpperCase())} ${chalk_1.default.dim(`(${mods.length})`)}`);
54
54
  mods.forEach((mod) => {
55
- logger_1.logger.log(` ${chalk_1.default.cyan('')} ${mod.displayName}`);
55
+ logger_1.logger.log(` ${chalk_1.default.cyan("")} ${mod.displayName}`);
56
56
  });
57
57
  }
58
58
  logger_1.logger.newLine();
@@ -71,7 +71,7 @@ async function getAvailableTemplates(templatesDir) {
71
71
  const templateDirs = await fs_extra_1.default.readdir(templatesDir);
72
72
  const templates = [];
73
73
  for (const dir of templateDirs) {
74
- const metadataPath = path_1.default.join(templatesDir, dir, 'template.json');
74
+ const metadataPath = path_1.default.join(templatesDir, dir, "template.json");
75
75
  if (await fs_extra_1.default.pathExists(metadataPath)) {
76
76
  const metadata = await fs_extra_1.default.readJSON(metadataPath);
77
77
  templates.push(metadata);
@@ -92,7 +92,7 @@ async function getAvailableModules(modulesDir) {
92
92
  continue;
93
93
  const moduleDirs = await fs_extra_1.default.readdir(categoryPath);
94
94
  for (const moduleDir of moduleDirs) {
95
- const metadataPath = path_1.default.join(categoryPath, moduleDir, 'module.json');
95
+ const metadataPath = path_1.default.join(categoryPath, moduleDir, "module.json");
96
96
  if (await fs_extra_1.default.pathExists(metadataPath)) {
97
97
  const metadata = await fs_extra_1.default.readJSON(metadataPath);
98
98
  modules.push(metadata);
package/dist/index.js CHANGED
@@ -11,39 +11,41 @@ const init_1 = require("./commands/init");
11
11
  const list_1 = require("./commands/list");
12
12
  const program = new commander_1.Command();
13
13
  program
14
- .name('stackkit')
15
- .description('Production-ready project generator and module CLI')
16
- .version('0.3.2');
14
+ .name("stackkit")
15
+ .description("Production-ready project generator and module CLI")
16
+ .version("0.3.2");
17
17
  // Init command
18
18
  program
19
- .command('init [project-name]')
20
- .description('Create a new project from a template')
21
- .option('-t, --template <template>', 'Template to use')
22
- .option('--pm <pm>', 'Package manager to use (npm, yarn, pnpm)')
23
- .option('--no-install', 'Skip installing dependencies')
24
- .option('--no-git', 'Skip git initialization')
25
- .option('-y, --yes', 'Skip prompts and use defaults')
19
+ .command("init [project-name]")
20
+ .description("Create a new project from a template")
21
+ .option("-t, --template <template>", "Template to use")
22
+ .option("--pm <pm>", "Package manager to use (npm, yarn, pnpm, bun)")
23
+ .option("--no-install", "Skip installing dependencies")
24
+ .option("--no-git", "Skip git initialization")
25
+ .option("-y, --yes", "Skip prompts and use defaults")
26
26
  .action(init_1.initCommand);
27
27
  // List command
28
28
  program
29
- .command('list')
30
- .description('List available templates and modules')
31
- .option('-t, --templates', 'List only templates')
32
- .option('-m, --modules', 'List only modules')
29
+ .command("list")
30
+ .description("List available templates and modules")
31
+ .option("-t, --templates", "List only templates")
32
+ .option("-m, --modules", "List only modules")
33
33
  .action(list_1.listCommand);
34
34
  // Add command
35
35
  program
36
- .command('add <module>')
37
- .description('Add a module to your existing project')
38
- .option('--provider <provider>', 'Specific provider/variant to use')
39
- .option('--force', 'Overwrite existing files')
40
- .option('--dry-run', 'Show what would be changed without making changes')
41
- .option('--no-install', 'Skip installing dependencies')
36
+ .command("add <module>")
37
+ .description("Add a module to your existing project")
38
+ .option("--provider <provider>", "Specific provider/variant to use")
39
+ .option("--force", "Overwrite existing files")
40
+ .option("--dry-run", "Show what would be changed without making changes")
41
+ .option("--no-install", "Skip installing dependencies")
42
42
  .action(add_1.addCommand);
43
43
  // Error handling
44
- program.on('command:*', () => {
45
- console.error(chalk_1.default.red(`\nInvalid command: ${program.args.join(' ')}\n`));
46
- console.log(chalk_1.default.yellow('Run stackkit --help for a list of available commands.\n'));
44
+ program.on("command:*", () => {
45
+ // Use logger for error and info
46
+ // logger.error and logger.log are not available here since logger is not imported, so fallback to process.stderr
47
+ process.stderr.write(chalk_1.default.red(`\nInvalid command: ${program.args.join(" ")}\n`));
48
+ process.stderr.write(chalk_1.default.yellow("Run stackkit --help for a list of available commands.\n"));
47
49
  process.exit(1);
48
50
  });
49
51
  program.parse();
@@ -3,14 +3,14 @@ export interface TemplateMetadata {
3
3
  displayName: string;
4
4
  description: string;
5
5
  tags: string[];
6
- defaultPackageManager: 'pnpm' | 'npm' | 'yarn';
6
+ defaultPackageManager: "pnpm" | "npm" | "yarn" | "bun";
7
7
  features: string[];
8
8
  }
9
9
  export interface ModuleMetadata {
10
10
  name: string;
11
11
  displayName: string;
12
12
  description: string;
13
- category: 'auth' | 'database' | 'ui' | 'other';
13
+ category: "auth" | "database" | "ui" | "other";
14
14
  supportedFrameworks: string[];
15
15
  dependencies: Record<string, string>;
16
16
  devDependencies?: Record<string, string>;
@@ -24,33 +24,33 @@ export interface EnvVar {
24
24
  required: boolean;
25
25
  }
26
26
  export interface ModulePatch {
27
- type: 'create-file' | 'modify-json' | 'append-env' | 'inject-code';
27
+ type: "create-file" | "modify-json" | "append-env" | "inject-code";
28
28
  description: string;
29
- [key: string]: any;
29
+ [key: string]: unknown;
30
30
  }
31
31
  export interface CreateFilePatch extends ModulePatch {
32
- type: 'create-file';
32
+ type: "create-file";
33
33
  source: string;
34
34
  destination: string;
35
35
  condition?: {
36
- router?: 'app' | 'pages';
37
- language?: 'ts' | 'js';
36
+ router?: "app" | "pages";
37
+ language?: "ts" | "js";
38
38
  };
39
39
  }
40
40
  export interface ModifyJsonPatch extends ModulePatch {
41
- type: 'modify-json';
41
+ type: "modify-json";
42
42
  file: string;
43
43
  operations: {
44
44
  path: string;
45
- value: any;
45
+ value: unknown;
46
46
  merge?: boolean;
47
47
  }[];
48
48
  }
49
49
  export interface ProjectInfo {
50
- framework: 'nextjs' | 'express' | 'react' | 'react-vite' | 'unknown';
51
- router: 'app' | 'pages' | 'unknown';
52
- language: 'ts' | 'js';
53
- packageManager: 'npm' | 'yarn' | 'pnpm';
50
+ framework: "nextjs" | "express" | "react" | "react-vite" | "unknown";
51
+ router: "app" | "pages" | "unknown";
52
+ language: "ts" | "js";
53
+ packageManager: "npm" | "yarn" | "pnpm" | "bun";
54
54
  hasAuth: boolean;
55
55
  hasPrisma: boolean;
56
56
  hasDatabase: boolean;
@@ -61,5 +61,5 @@ export interface CLIOptions {
61
61
  dryRun?: boolean;
62
62
  yes?: boolean;
63
63
  noInstall?: boolean;
64
- pm?: 'npm' | 'yarn' | 'pnpm';
64
+ pm?: "npm" | "yarn" | "pnpm" | "bun";
65
65
  }
@@ -3,7 +3,7 @@ export interface CodeInjection {
3
3
  code: string;
4
4
  description: string;
5
5
  }
6
- export declare function injectCode(filePath: string, injection: CodeInjection, position: 'append' | 'prepend' | {
6
+ export declare function injectCode(filePath: string, injection: CodeInjection, position: "append" | "prepend" | {
7
7
  after: string;
8
8
  } | {
9
9
  before: string;
@@ -13,7 +13,7 @@ async function injectCode(filePath, injection, position, options = {}) {
13
13
  if (!(await fs_extra_1.default.pathExists(filePath))) {
14
14
  throw new Error(`File not found: ${filePath}`);
15
15
  }
16
- let content = await fs_extra_1.default.readFile(filePath, 'utf-8');
16
+ let content = await fs_extra_1.default.readFile(filePath, "utf-8");
17
17
  // Check if already injected
18
18
  const startMarker = CODE_MARKER_START(injection.id);
19
19
  if (content.includes(startMarker) && !options.force) {
@@ -26,13 +26,13 @@ async function injectCode(filePath, injection, position, options = {}) {
26
26
  // Prepare the code block with markers
27
27
  const markedCode = `\n${startMarker}\n${injection.code}\n${CODE_MARKER_END(injection.id)}\n`;
28
28
  // Inject based on position
29
- if (position === 'append') {
29
+ if (position === "append") {
30
30
  content += markedCode;
31
31
  }
32
- else if (position === 'prepend') {
32
+ else if (position === "prepend") {
33
33
  content = markedCode + content;
34
34
  }
35
- else if ('after' in position) {
35
+ else if ("after" in position) {
36
36
  const index = content.indexOf(position.after);
37
37
  if (index === -1) {
38
38
  throw new Error(`Could not find marker: ${position.after}`);
@@ -40,14 +40,14 @@ async function injectCode(filePath, injection, position, options = {}) {
40
40
  const insertPos = index + position.after.length;
41
41
  content = content.slice(0, insertPos) + markedCode + content.slice(insertPos);
42
42
  }
43
- else if ('before' in position) {
43
+ else if ("before" in position) {
44
44
  const index = content.indexOf(position.before);
45
45
  if (index === -1) {
46
46
  throw new Error(`Could not find marker: ${position.before}`);
47
47
  }
48
48
  content = content.slice(0, index) + markedCode + content.slice(index);
49
49
  }
50
- await fs_extra_1.default.writeFile(filePath, content, 'utf-8');
50
+ await fs_extra_1.default.writeFile(filePath, content, "utf-8");
51
51
  }
52
52
  function removeInjection(content, id) {
53
53
  const startMarker = CODE_MARKER_START(id);
@@ -1,4 +1,4 @@
1
- import { ProjectInfo } from '../types';
1
+ import { ProjectInfo } from "../types";
2
2
  export declare function detectProjectInfo(targetDir: string): Promise<ProjectInfo>;
3
3
  export declare function getRouterBasePath(projectInfo: ProjectInfo): string;
4
4
  export declare function getLibPath(projectInfo: ProjectInfo): string;