stackkit 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -31,11 +31,11 @@ npx stackkit doctor
31
31
 
32
32
  ## Supported Technologies
33
33
 
34
- - **Frameworks**: Next.js, React (Vite), Express
34
+ - **Frameworks**: Next.js, React, Express
35
35
  - **Databases**: Prisma (PostgreSQL, MySQL, SQLite), Mongoose (MongoDB)
36
36
  - **Auth**: Better Auth, Auth.js
37
37
 
38
38
  ## Documentation
39
39
 
40
- - [StackKit Docs](https://stack-kit.dev)
40
+ - [StackKit Docs](https://stack-kit.com)[https://stackkit.tariqul.dev]
41
41
  - [GitHub Repository](https://github.com/tariqul420/stackkit)
package/dist/cli/add.js CHANGED
@@ -15,13 +15,14 @@ const files_1 = require("../lib/fs/files");
15
15
  const logger_1 = require("../lib/ui/logger");
16
16
  const package_manager_1 = require("../lib/pm/package-manager");
17
17
  const database_config_1 = require("../lib/database/database-config");
18
+ const package_root_1 = require("../lib/utils/package-root");
18
19
  async function addCommand(module, options) {
19
20
  try {
20
21
  const projectRoot = process.cwd();
21
22
  const spinner = logger_1.logger.startSpinner("Detecting project...");
22
23
  const projectInfo = await (0, detect_1.detectProjectInfo)(projectRoot);
23
24
  spinner.succeed(`Detected ${projectInfo.framework} (${projectInfo.router} router, ${projectInfo.language})`);
24
- const moduleMetadata = await loadModuleMetadata(path_1.default.join(__dirname, "..", "..", "..", "modules"), module, options.provider);
25
+ const moduleMetadata = await loadModuleMetadata(path_1.default.join((0, package_root_1.getPackageRoot)(), "modules"), module, options.provider);
25
26
  if (!moduleMetadata) {
26
27
  logger_1.logger.error(`Module "${module}" not found`);
27
28
  process.exit(1);
@@ -87,7 +88,7 @@ async function addCommand(module, options) {
87
88
  logger_1.logger.warn("Dry run mode - no changes will be made");
88
89
  logger_1.logger.newLine();
89
90
  }
90
- await applyModulePatches(projectRoot, projectInfo, moduleMetadata, path_1.default.join(__dirname, "..", "..", "modules"), module, options);
91
+ await applyModulePatches(projectRoot, projectInfo, moduleMetadata, path_1.default.join((0, package_root_1.getPackageRoot)(), "modules"), module, options);
91
92
  if (moduleMetadata.frameworkPatches && !options.dryRun) {
92
93
  await applyFrameworkPatches(projectRoot, moduleMetadata.frameworkPatches, projectInfo.framework);
93
94
  }
@@ -184,7 +185,6 @@ async function loadGeneratorAndMerge(metadata, modulePath) {
184
185
  const generatorPath = path_1.default.join(modulePath, "generator.json");
185
186
  if (await fs_extra_1.default.pathExists(generatorPath)) {
186
187
  const generator = await fs_extra_1.default.readJSON(generatorPath);
187
- // Merge envVars, dependencies, etc.
188
188
  if (generator.envVars) {
189
189
  metadata.envVars = metadata.envVars || [];
190
190
  for (const [key, value] of Object.entries(generator.envVars)) {
@@ -197,10 +197,6 @@ async function loadGeneratorAndMerge(metadata, modulePath) {
197
197
  if (generator.devDependencies) {
198
198
  metadata.devDependencies = { ...metadata.devDependencies, ...generator.devDependencies };
199
199
  }
200
- if (generator.scripts) {
201
- // Perhaps add to metadata, but currently not used
202
- }
203
- // For operations, perhaps add to patches or something, but for now, keep manual
204
200
  }
205
201
  return metadata;
206
202
  }
@@ -17,6 +17,7 @@ const logger_1 = require("../lib/ui/logger");
17
17
  const framework_utils_1 = require("../lib/framework/framework-utils");
18
18
  const module_discovery_1 = require("../lib/discovery/module-discovery");
19
19
  const code_generator_1 = require("../lib/generation/code-generator");
20
+ const package_root_1 = require("../lib/utils/package-root");
20
21
  async function createProject(projectName, options) {
21
22
  logger_1.logger.newLine();
22
23
  logger_1.logger.log(chalk_1.default.bold.cyan("📦 Create StackKit App"));
@@ -32,20 +33,8 @@ async function createProject(projectName, options) {
32
33
  showNextSteps(config);
33
34
  }
34
35
  async function getProjectConfig(projectName, options) {
35
- // Resolve modules directory (dist first, then package root)
36
- const modulesCandidates = [
37
- path_1.default.join(__dirname, "..", "..", "..", "modules"),
38
- path_1.default.join(__dirname, "..", "..", "..", "..", "modules"),
39
- ];
40
- let modulesDir;
41
- for (const c of modulesCandidates) {
42
- if (await fs_extra_1.default.pathExists(c)) {
43
- modulesDir = c;
44
- break;
45
- }
46
- }
47
- const discoveredModules = await (0, module_discovery_1.discoverModules)(modulesDir || modulesCandidates[1]);
48
- // Detect flags or `--yes` after `create`; project-name-only remains interactive
36
+ const modulesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), 'modules');
37
+ const discoveredModules = await (0, module_discovery_1.discoverModules)(modulesDir);
49
38
  const argv = process.argv.slice(2);
50
39
  const createIndex = argv.indexOf('create');
51
40
  const argsAfterCreate = createIndex >= 0 ? argv.slice(createIndex + 1) : [];
@@ -63,7 +52,6 @@ async function getProjectConfig(projectName, options) {
63
52
  packageManager: "pnpm",
64
53
  };
65
54
  }
66
- // Validate options using discovered modules (if any discovered)
67
55
  const framework = (options && (options.framework || options.f)) || undefined;
68
56
  if (discoveredModules.frameworks && discoveredModules.frameworks.length > 0) {
69
57
  const validFrameworks = discoveredModules.frameworks.map(f => f.name);
@@ -75,7 +63,6 @@ async function getProjectConfig(projectName, options) {
75
63
  let allValidDatabases = [];
76
64
  if (discoveredModules.databases && discoveredModules.databases.length > 0) {
77
65
  const validDatabases = (0, module_discovery_1.getValidDatabaseOptions)(discoveredModules.databases);
78
- // Also allow base database names like 'prisma', 'mongoose'
79
66
  const validBaseDatabases = discoveredModules.databases.map(db => db.name);
80
67
  allValidDatabases = [...validDatabases, ...validBaseDatabases];
81
68
  if (db && !allValidDatabases.includes(db)) {
@@ -111,7 +98,6 @@ async function getProjectConfig(projectName, options) {
111
98
  auth = authOpt;
112
99
  }
113
100
  const finalFramework = (framework || "nextjs");
114
- // Validate auth compatibility
115
101
  if (auth === "authjs" && (database !== "prisma" || finalFramework !== "nextjs")) {
116
102
  throw new Error("Auth.js is only supported with Next.js and Prisma database");
117
103
  }
@@ -128,7 +114,6 @@ async function getProjectConfig(projectName, options) {
128
114
  packageManager: (pm || "pnpm"),
129
115
  };
130
116
  }
131
- // Interactive prompts
132
117
  const answers = (await inquirer_1.default.prompt([
133
118
  {
134
119
  type: "input",
@@ -151,10 +136,13 @@ async function getProjectConfig(projectName, options) {
151
136
  type: "list",
152
137
  name: "framework",
153
138
  message: "Select framework:",
154
- choices: discoveredModules.frameworks.map(f => ({
155
- name: f.displayName,
156
- value: f.name
157
- })),
139
+ choices: (discoveredModules.frameworks && discoveredModules.frameworks.length > 0)
140
+ ? discoveredModules.frameworks.map(f => ({ name: f.displayName, value: f.name }))
141
+ : [
142
+ { name: 'Next.js', value: 'nextjs' },
143
+ { name: 'Express.js', value: 'express' },
144
+ { name: 'React (Vite)', value: 'react' },
145
+ ],
158
146
  },
159
147
  {
160
148
  type: "list",
@@ -232,7 +220,6 @@ async function generateProject(config, targetDir, options) {
232
220
  copySpinner.fail("Failed to create project files");
233
221
  throw error;
234
222
  }
235
- // Install dependencies
236
223
  if (options?.install !== false && !(options?.['skip-install'] || options?.skipInstall)) {
237
224
  const installSpinner = logger_1.logger.startSpinner("Installing dependencies...");
238
225
  try {
@@ -244,7 +231,6 @@ async function generateProject(config, targetDir, options) {
244
231
  throw error;
245
232
  }
246
233
  }
247
- // Run post-install commands (skip if install was skipped)
248
234
  if (postInstallCommands.length > 0 && options?.install !== false && !(options?.['skip-install'] || options?.skipInstall)) {
249
235
  const postInstallSpinner = logger_1.logger.startSpinner("Running post-install commands...");
250
236
  try {
@@ -258,7 +244,6 @@ async function generateProject(config, targetDir, options) {
258
244
  throw error;
259
245
  }
260
246
  }
261
- // Initialize git
262
247
  if (options?.git !== false && !(options?.['no-git'] || options?.noGit)) {
263
248
  const gitSpinner = logger_1.logger.startSpinner("Initializing git repository...");
264
249
  try {
@@ -271,28 +256,13 @@ async function generateProject(config, targetDir, options) {
271
256
  }
272
257
  }
273
258
  async function composeTemplate(config, targetDir) {
274
- // Resolve templates/modules paths
275
- const templatesCandidates = [
276
- path_1.default.join(__dirname, "..", "..", "..", "templates"),
277
- path_1.default.join(__dirname, "..", "..", "..", "..", "templates"),
278
- ];
279
- const modulesCandidates2 = [
280
- path_1.default.join(__dirname, "..", "..", "..", "modules"),
281
- path_1.default.join(__dirname, "..", "..", "..", "..", "modules"),
282
- ];
283
- const templatesDir = (await (async () => { for (const c of templatesCandidates)
284
- if (await fs_extra_1.default.pathExists(c))
285
- return c; return templatesCandidates[1]; })());
286
- const modulesDirForGenerator = (await (async () => { for (const c of modulesCandidates2)
287
- if (await fs_extra_1.default.pathExists(c))
288
- return c; return modulesCandidates2[1]; })());
259
+ const packageRoot = (0, package_root_1.getPackageRoot)();
260
+ const templatesDir = path_1.default.join(packageRoot, 'templates');
261
+ const modulesDirForGenerator = path_1.default.join(packageRoot, 'modules');
289
262
  await fs_extra_1.default.ensureDir(targetDir);
290
- // Load framework configuration
291
263
  const frameworkConfig = await framework_utils_1.FrameworkUtils.loadFrameworkConfig(config.framework, templatesDir);
292
- // Initialize advanced code generator
293
264
  const generator = new code_generator_1.AdvancedCodeGenerator(frameworkConfig);
294
265
  await generator.loadGenerators(modulesDirForGenerator);
295
- // Generate project using advanced code generator
296
266
  const features = [];
297
267
  const postInstallCommands = await generator.generate({
298
268
  framework: config.framework,
@@ -300,14 +270,12 @@ async function composeTemplate(config, targetDir) {
300
270
  auth: config.auth === 'none' ? undefined : config.auth,
301
271
  prismaProvider: config.prismaProvider,
302
272
  }, features, targetDir);
303
- // Update project name in package.json
304
273
  const packageJsonPath = path_1.default.join(targetDir, "package.json");
305
274
  if (await fs_extra_1.default.pathExists(packageJsonPath)) {
306
275
  const packageJson = await fs_extra_1.default.readJson(packageJsonPath);
307
276
  packageJson.name = config.projectName;
308
277
  await fs_extra_1.default.writeJson(packageJsonPath, packageJson, { spaces: 2 });
309
278
  }
310
- // Ensure .env exists: if .env.example was copied from the template, create .env from it
311
279
  try {
312
280
  const envExamplePath = path_1.default.join(targetDir, ".env.example");
313
281
  const envPath = path_1.default.join(targetDir, ".env");
@@ -317,12 +285,11 @@ async function composeTemplate(config, targetDir) {
317
285
  }
318
286
  }
319
287
  catch {
320
- // non-fatal
288
+ // Non-fatal: .env creation from .env.example is optional
321
289
  }
322
290
  if (config.language === "javascript") {
323
291
  await (0, js_conversion_1.convertToJavaScript)(targetDir, config.framework);
324
292
  }
325
- // For now, return empty array as post-install commands are handled by the generator
326
293
  return postInstallCommands;
327
294
  }
328
295
  function showNextSteps(config) {
@@ -229,13 +229,11 @@ function detectDatabaseModules(packageJson) {
229
229
  }
230
230
  async function checkKeyFiles(projectRoot, projectType, authModules, databaseModules) {
231
231
  const checks = [];
232
- // Check .env.example
233
232
  const envExampleExists = await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, ".env.example"));
234
233
  checks.push({
235
234
  status: envExampleExists ? "success" : "warning",
236
235
  message: envExampleExists ? ".env.example file found" : ".env.example file missing (recommended for documentation)",
237
236
  });
238
- // Check Prisma schema
239
237
  if (databaseModules.includes("prisma")) {
240
238
  const schemaExists = await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, "prisma", "schema.prisma"));
241
239
  checks.push({
@@ -243,7 +241,6 @@ async function checkKeyFiles(projectRoot, projectType, authModules, databaseModu
243
241
  message: schemaExists ? "Prisma schema found" : "Prisma schema missing (required for Prisma)",
244
242
  });
245
243
  }
246
- // Check auth routes
247
244
  if (authModules.length > 0 && projectType === "nextjs") {
248
245
  const authRoutesExist = await checkAuthRoutesExist(projectRoot, projectType);
249
246
  checks.push({
@@ -278,7 +275,6 @@ async function checkEnvFiles(projectRoot, authModules, databaseModules) {
278
275
  const requiredKeys = [];
279
276
  const missing = [];
280
277
  const present = [];
281
- // Determine required env keys
282
278
  if (databaseModules.includes("prisma")) {
283
279
  requiredKeys.push("DATABASE_URL");
284
280
  }
@@ -288,7 +284,6 @@ async function checkEnvFiles(projectRoot, authModules, databaseModules) {
288
284
  if (authModules.includes("better-auth")) {
289
285
  requiredKeys.push("BETTER_AUTH_SECRET", "BETTER_AUTH_URL");
290
286
  }
291
- // Check env files
292
287
  const envPaths = [".env", ".env.local"];
293
288
  let envContent = "";
294
289
  for (const envPath of envPaths) {
@@ -305,7 +300,6 @@ async function checkEnvFiles(projectRoot, authModules, databaseModules) {
305
300
  });
306
301
  return { checks, envStatus: { missing: requiredKeys, present: [] } };
307
302
  }
308
- // Parse env content
309
303
  const envLines = envContent.split("\n").map(line => line.trim()).filter(line => line && !line.startsWith("#"));
310
304
  const envVars = new Set(envLines.map(line => line.split("=")[0]));
311
305
  for (const key of requiredKeys) {
package/dist/cli/list.js CHANGED
@@ -8,6 +8,7 @@ const chalk_1 = __importDefault(require("chalk"));
8
8
  const fs_extra_1 = __importDefault(require("fs-extra"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const logger_1 = require("../lib/ui/logger");
11
+ const package_root_1 = require("../lib/utils/package-root");
11
12
  async function listCommand(options) {
12
13
  const showFrameworks = !options.modules || options.frameworks;
13
14
  const showModules = !options.frameworks || options.modules;
@@ -17,7 +18,7 @@ async function listCommand(options) {
17
18
  let hasFrameworks = false;
18
19
  let hasModules = false;
19
20
  if (showFrameworks) {
20
- const templatesDir = path_1.default.join(__dirname, "..", "..", "..", "..", "templates");
21
+ const templatesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), "templates");
21
22
  const frameworks = await getAvailableFrameworks(templatesDir);
22
23
  if (frameworks.length > 0) {
23
24
  hasFrameworks = true;
@@ -30,14 +31,12 @@ async function listCommand(options) {
30
31
  logger_1.logger.newLine();
31
32
  }
32
33
  }
33
- // List modules
34
34
  if (showModules) {
35
- const modulesDir = path_1.default.join(__dirname, "..", "..", "..", "modules");
35
+ const modulesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), "modules");
36
36
  const modules = await getAvailableModules(modulesDir);
37
37
  if (modules.length > 0) {
38
38
  hasModules = true;
39
39
  logger_1.logger.log(chalk_1.default.bold.magenta("MODULES"));
40
- // Group by category
41
40
  const grouped = modules.reduce((acc, mod) => {
42
41
  if (!acc[mod.category]) {
43
42
  acc[mod.category] = [];
@@ -55,7 +54,6 @@ async function listCommand(options) {
55
54
  const isLastMod = modIndex === mods.length - 1;
56
55
  const modPrefix = isLastCategory ? (isLastMod ? " └──" : " ├──") : (isLastMod ? "│ └──" : "│ ├──");
57
56
  logger_1.logger.log(` ${chalk_1.default.gray(modPrefix)} ${chalk_1.default.green(mod.displayName)}`);
58
- // Show additional details for database modules
59
57
  if (mod.category === "database" && mod.name === "prisma") {
60
58
  const providerPrefix = isLastCategory ? (isLastMod ? " └──" : " ├──") : (isLastMod ? "│ └──" : "│ ├──");
61
59
  logger_1.logger.log(` ${chalk_1.default.gray(providerPrefix)} ${chalk_1.default.dim("Providers: PostgreSQL, MongoDB, MySQL, SQLite")}`);
@@ -7,6 +7,7 @@ exports.convertToJavaScript = convertToJavaScript;
7
7
  /* eslint-disable @typescript-eslint/no-require-imports */
8
8
  const fs_extra_1 = __importDefault(require("fs-extra"));
9
9
  const path_1 = __importDefault(require("path"));
10
+ const package_root_1 = require("../utils/package-root");
10
11
  const baseDirs = {
11
12
  express: "./src",
12
13
  "react": "./src",
@@ -165,7 +166,7 @@ async function convertToJavaScript(targetDir, framework) {
165
166
  };
166
167
  await replaceAliases(targetDir);
167
168
  }
168
- const templatesRoot = path_1.default.join(__dirname, "..", "..", "..", "templates");
169
+ const templatesRoot = path_1.default.join((0, package_root_1.getPackageRoot)(), "templates");
169
170
  const templateName = framework;
170
171
  let fileReplacements = [];
171
172
  let jsScripts = null;
@@ -11,6 +11,7 @@ exports.getCompatibleAuthOptions = getCompatibleAuthOptions;
11
11
  exports.getDatabaseChoices = getDatabaseChoices;
12
12
  const fs_extra_1 = __importDefault(require("fs-extra"));
13
13
  const path_1 = __importDefault(require("path"));
14
+ const package_root_1 = require("../utils/package-root");
14
15
  /**
15
16
  * Discover all available modules from the modules directory
16
17
  */
@@ -20,9 +21,21 @@ async function discoverModules(modulesDir) {
20
21
  databases: [],
21
22
  auth: [],
22
23
  };
23
- if (!(await fs_extra_1.default.pathExists(modulesDir))) {
24
- return discovered;
24
+ // If modulesDir isn't provided or doesn't exist, try common locations
25
+ const candidates = [];
26
+ if (modulesDir)
27
+ candidates.push(modulesDir);
28
+ candidates.push(path_1.default.join((0, package_root_1.getPackageRoot)(), 'modules')); // package root
29
+ let resolvedModulesDir;
30
+ for (const c of candidates) {
31
+ if (await fs_extra_1.default.pathExists(c)) {
32
+ resolvedModulesDir = c;
33
+ break;
34
+ }
25
35
  }
36
+ if (!resolvedModulesDir)
37
+ return discovered;
38
+ modulesDir = resolvedModulesDir;
26
39
  // Discover frameworks from templates directory
27
40
  const templatesDir = path_1.default.join(modulesDir, '..', 'templates');
28
41
  if (await fs_extra_1.default.pathExists(templatesDir)) {
@@ -62,6 +75,11 @@ async function discoverModules(modulesDir) {
62
75
  if (await fs_extra_1.default.pathExists(moduleJsonPath)) {
63
76
  try {
64
77
  const metadata = await fs_extra_1.default.readJson(moduleJsonPath);
78
+ // Ensure name/displayName fallbacks
79
+ if (!metadata.name)
80
+ metadata.name = moduleName;
81
+ if (!metadata.displayName)
82
+ metadata.displayName = moduleName;
65
83
  discovered.databases.push(metadata);
66
84
  }
67
85
  catch {
@@ -80,6 +98,10 @@ async function discoverModules(modulesDir) {
80
98
  if (await fs_extra_1.default.pathExists(moduleJsonPath)) {
81
99
  try {
82
100
  const metadata = await fs_extra_1.default.readJson(moduleJsonPath);
101
+ if (!metadata.name)
102
+ metadata.name = moduleName;
103
+ if (!metadata.displayName)
104
+ metadata.displayName = moduleName;
83
105
  discovered.auth.push(metadata);
84
106
  }
85
107
  catch {
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.AdvancedCodeGenerator = void 0;
37
37
  const fs = __importStar(require("fs-extra"));
38
38
  const path = __importStar(require("path"));
39
+ const package_root_1 = require("../utils/package-root");
39
40
  class AdvancedCodeGenerator {
40
41
  constructor(frameworkConfig) {
41
42
  this.generators = new Map();
@@ -44,7 +45,6 @@ class AdvancedCodeGenerator {
44
45
  }
45
46
  async loadGenerators(modulesPath) {
46
47
  const moduleTypes = ['auth', 'database'];
47
- // Load module generators
48
48
  for (const type of moduleTypes) {
49
49
  const typePath = path.join(modulesPath, type);
50
50
  if (await fs.pathExists(typePath)) {
@@ -54,13 +54,11 @@ class AdvancedCodeGenerator {
54
54
  if (await fs.pathExists(generatorPath)) {
55
55
  try {
56
56
  const config = await fs.readJson(generatorPath);
57
- // Also load module.json for additional metadata like postInstall
58
57
  const modulePath = path.join(typePath, moduleName, 'module.json');
59
58
  if (await fs.pathExists(modulePath)) {
60
59
  try {
61
60
  const moduleConfig = await fs.readJson(modulePath);
62
61
  if (moduleConfig.postInstall && Array.isArray(moduleConfig.postInstall)) {
63
- // Store postInstall commands with the generator for later use
64
62
  config.postInstall = moduleConfig.postInstall;
65
63
  }
66
64
  }
@@ -375,28 +373,18 @@ class AdvancedCodeGenerator {
375
373
  }
376
374
  }
377
375
  async copyTemplate(frameworkName, outputPath) {
378
- const candidates = [
379
- path.resolve(__dirname, '..', '..', 'templates'), // dist/templates (when bundled)
380
- path.resolve(__dirname, '..', '..', '..', 'templates'), // package root templates
381
- ];
382
- let templateBase;
383
- for (const c of candidates) {
384
- const p = path.join(c, frameworkName);
385
- if (await fs.pathExists(p)) {
386
- templateBase = p;
387
- break;
388
- }
376
+ const packageRoot = (0, package_root_1.getPackageRoot)();
377
+ const templatePath = path.join(packageRoot, 'templates', frameworkName);
378
+ if (await fs.pathExists(templatePath)) {
379
+ await fs.copy(templatePath, outputPath, {
380
+ filter: (src) => {
381
+ const relativePath = path.relative(templatePath, src);
382
+ return relativePath !== 'template.json' &&
383
+ relativePath !== 'node_modules' &&
384
+ !relativePath.startsWith('node_modules/');
385
+ }
386
+ });
389
387
  }
390
- if (!templateBase)
391
- return;
392
- await fs.copy(templateBase, outputPath, {
393
- filter: (src) => {
394
- const relativePath = path.relative(templateBase, src);
395
- return relativePath !== 'template.json' &&
396
- relativePath !== 'node_modules' &&
397
- !relativePath.startsWith('node_modules/');
398
- }
399
- });
400
388
  }
401
389
  processOperationTemplates(operation, context) {
402
390
  const processed = { ...operation };
@@ -456,27 +444,12 @@ class AdvancedCodeGenerator {
456
444
  }
457
445
  else if (operation.source) {
458
446
  // Find the source file path relative to the module/template directory
459
- // Resolve modules/templates base paths (try both dist and package root)
460
- const modulesCandidates = [
461
- path.resolve(__dirname, '..', '..', 'modules'),
462
- path.resolve(__dirname, '..', '..', '..', 'modules'),
463
- ];
464
- const templatesCandidates = [
465
- path.resolve(__dirname, '..', '..', 'templates'),
466
- path.resolve(__dirname, '..', '..', '..', 'templates'),
467
- ];
468
- const resolveExisting = async (cands) => {
469
- for (const c of cands) {
470
- if (await fs.pathExists(c))
471
- return c;
472
- }
473
- return undefined;
474
- };
475
- const modulesPathResolved = await resolveExisting(modulesCandidates);
476
- const templatesPathResolved = await resolveExisting(templatesCandidates);
447
+ const packageRoot = (0, package_root_1.getPackageRoot)();
448
+ const modulesPath = path.join(packageRoot, 'modules');
449
+ const templatesPath = path.join(packageRoot, 'templates');
477
450
  const moduleBasePath = operation.generatorType === 'framework'
478
- ? path.join(templatesPathResolved || templatesCandidates[0], operation.generator)
479
- : path.join(modulesPathResolved || modulesCandidates[0], operation.generatorType, operation.generator);
451
+ ? path.join(templatesPath, operation.generator)
452
+ : path.join(modulesPath, operation.generatorType, operation.generator);
480
453
  const sourcePath = path.join(moduleBasePath, 'files', operation.source);
481
454
  // Check if source file exists
482
455
  if (await fs.pathExists(sourcePath)) {
@@ -551,7 +524,7 @@ class AdvancedCodeGenerator {
551
524
  processedContentTop = this.processTemplate(patchOp.content, context).trim();
552
525
  }
553
526
  else if (patchOp.source) {
554
- const modulesPath = path.join(__dirname, '..', '..', 'modules');
527
+ const modulesPath = path.join((0, package_root_1.getPackageRoot)(), 'modules');
555
528
  const sourcePath = path.join(modulesPath, operation.generatorType, operation.generator, 'files', patchOp.source);
556
529
  if (await fs.pathExists(sourcePath)) {
557
530
  processedContentTop = await fs.readFile(sourcePath, 'utf-8');
@@ -569,7 +542,7 @@ class AdvancedCodeGenerator {
569
542
  processedContentBottom = this.processTemplate(patchOp.content, context).trim();
570
543
  }
571
544
  else if (patchOp.source) {
572
- const modulesPath = path.join(__dirname, '..', '..', 'modules');
545
+ const modulesPath = path.join((0, package_root_1.getPackageRoot)(), 'modules');
573
546
  const sourcePath = path.join(modulesPath, operation.generatorType, operation.generator, 'files', patchOp.source);
574
547
  if (await fs.pathExists(sourcePath)) {
575
548
  processedContentBottom = await fs.readFile(sourcePath, 'utf-8');
@@ -0,0 +1 @@
1
+ export declare function getPackageRoot(): string;
@@ -0,0 +1,45 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getPackageRoot = getPackageRoot;
37
+ const path = __importStar(require("path"));
38
+ function getPackageRoot() {
39
+ try {
40
+ return path.dirname(require.resolve('stackkit/package.json'));
41
+ }
42
+ catch {
43
+ return path.resolve(__dirname, '..', '..', '..');
44
+ }
45
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stackkit",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Production-ready CLI to create and extend JavaScript or TypeScript apps with modular stacks.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -71,7 +71,6 @@
71
71
  "@types/validate-npm-package-name": "^4.0.2",
72
72
  "typescript": "^5.3.3",
73
73
  "recast": "^0.20.5",
74
- "@babel/core": "^7.28.5",
75
74
  "@babel/plugin-transform-typescript": "^7.28.5",
76
75
  "@babel/parser": "^7.28.5",
77
76
  "@babel/plugin-transform-react-jsx": "^7.27.1"
@@ -1,4 +1,4 @@
1
- # React + Vite Template
1
+ # React Template
2
2
 
3
3
  Production-ready React starter with TypeScript, Vite, and essential libraries.
4
4
 
@@ -1,56 +0,0 @@
1
- # React + Vite Template
2
-
3
- Production-ready React starter with TypeScript, Vite, and essential libraries.
4
-
5
- ## Quick Start
6
-
7
- ```bash
8
- pnpm install
9
- pnpm dev
10
- ```
11
-
12
- ## Features
13
-
14
- - React 19 with TypeScript
15
- - Vite for fast development
16
- - React Router for routing
17
- - TanStack Query for data fetching
18
- - Tailwind CSS for styling
19
- - ESLint for code quality
20
-
21
- ## Scripts
22
-
23
- - `pnpm dev` - Start development server
24
- - `pnpm build` - Build for production
25
- - `pnpm preview` - Preview production build
26
- - `pnpm lint` - Run linter
27
-
28
- ## Environment Variables
29
-
30
- Copy `.env.example` to `.env` and configure:
31
-
32
- ```env
33
- VITE_API_URL=http://localhost:3000/api
34
- VITE_APP_NAME=My App
35
- ```
36
-
37
- ## Project Structure
38
-
39
- ```
40
- src/
41
- ├── api/ # API client
42
- ├── components/ # UI components
43
- ├── hooks/ # Custom hooks
44
- ├── lib/ # Utilities
45
- ├── pages/ # Route pages
46
- ├── types/ # TypeScript types
47
- └── utils/ # Helper functions
48
- ```
49
-
50
- ## Deployment
51
-
52
- ```bash
53
- pnpm build
54
- ```
55
-
56
- Deploy the `dist` folder to Vercel, Netlify, or any static hosting service.