@shakil-dev/shakil-stack 1.2.0 → 1.3.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.
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ education, socio-economic status, nationality, personal appearance, race,
10
+ religion, or sexual identity and orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an
52
+ appointed representative at an online or offline event. Representation of a
53
+ project may be further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team. All complaints will be reviewed and
59
+ investigated and will result in a response that is deemed necessary and
60
+ appropriate to the circumstances. The project team will maintain confidentiality
61
+ with regard to the reporter of an incident. Further details of specific
62
+ enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
71
+ version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shakil Ahmed Billal
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,79 +1,113 @@
1
- # Shakil-Stack Project Generator 🚀
1
+ # 🚀 Shakil-Stack
2
2
 
3
- **Shakil-Stack** is a powerful full-stack project generator CLI that scaffolds a robust, production-ready environment based on the **EchoNet** backend architecture and a modern **Next.js** frontend.
3
+ [![npm version](https://img.shields.io/npm/v/@shakil-dev/shakil-stack.svg?style=flat-square)](https://www.npmjs.com/package/@shakil-dev/shakil-stack)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
5
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/shakil-ahmed-billal/shakil-stack-cli/publish.yml?branch=main&style=flat-square)](https://github.com/shakil-ahmed-billal/shakil-stack-cli/actions)
4
6
 
5
- ## Features
7
+ **Shakil-Stack** is a high-performance, developer-first full-stack project generator. It scaffolds production-ready applications mirroring the **EchoNet** backend architecture paired with a state-of-the-art **Next.js** frontend.
6
8
 
7
- - **🛡️ EchoNet-Style Backend**:
8
- - **Architecture**: Clean `src/app/...` structure (config, middleware, routes, utils).
9
- - **Database**: Prisma 7+ with PostgreSQL adapter.
10
- - **Authentication**: Pre-configured **Better Auth** with User, Session, and Account models.
11
- - **Security**: Helmet, Express Rate Limit, and Request Sanitizer.
12
- - **Error Handling**: Global error handler with `ApiError` support.
13
- - **Validation**: Zod-ready structure.
14
- - **🌐 Next.js Frontend**:
15
- - Modern Next.js (App Router, TypeScript, Tailwind CSS).
16
- - Pre-defined project folders: `config`, `hooks`, `lib`, `services`, `types`.
17
- - **🛠️ Interactive Setup**: Choose your package manager (npm, pnpm, yarn) and auto-install dependencies.
9
+ ---
10
+
11
+ ## 🌟 Key Features
12
+
13
+ ### 🛡️ Backend Excellence (EchoNet Style)
14
+ - **Modular Architecture**: Clean, scalable `src/app/module` pattern.
15
+ - **Prisma 7+**: Next-gen database ORM with pre-configured PostgreSQL adapters.
16
+ - **Better Auth Integration**: Pre-built authentication schemas (User, Session, Account).
17
+ - **Security First**: Integrated Helmet, CORS, Rate Limiting, and XSS Sanitization.
18
+ - **Robust Error Handling**: Centralized global error handler and structured `ApiError` class.
18
19
 
19
- ## 🚀 Getting Started
20
+ ### 🌐 Modern Frontend (Next.js)
21
+ - **App Router**: Leveraging the latest Next.js 14/15 patterns.
22
+ - **TypeScript & Tailwind**: Pre-configured for visual excellence and type safety.
23
+ - **Clean Structure**: Dedicated directories for hooks, services, lib, and types.
20
24
 
21
- You can generate a new project instantly using `npx`:
25
+ ### 🛠️ Developer Experience (CLI)
26
+ - **One-Command Scaffolding**: Setup your entire stack in seconds.
27
+ - **Smart Generation**: Scaffold modules (Controller, Service, Route) with zero boilerplate.
28
+ - **Built-in Utilities**: Quick access to Prisma and build commands.
29
+
30
+ ---
22
31
 
32
+ ## 🚀 Commands Guide
33
+
34
+ ### 1. Initialize a New Project
35
+ Create your full-stack dream project interactively:
23
36
  ```bash
24
- npx @shakil-dev/shakil-stack my-awesome-project
37
+ npx @shakil-dev/shakil-stack init my-awesome-app
25
38
  ```
26
39
 
27
- ### Or, if already installed globally:
40
+ ### 2. Scaffold a New Module (g)
41
+ Generate a complete module with all layers instantly:
42
+ ```bash
43
+ # Must be run in the project root
44
+ shakil-stack g module Product
45
+ ```
46
+ **Generated Files:**
47
+ - `product.controller.ts`: Request/Response handling.
48
+ - `product.service.ts`: Business logic & Database interaction.
49
+ - `product.route.ts`: API endpoint definitions.
50
+ - `product.interface.ts`: Data types and contracts.
51
+ - `product.validation.ts`: Zod schema validation.
52
+ - `product.constant.ts`: Reusable constants.
53
+
54
+ ### 3. Production Build
55
+ Prepare your application for the real world:
56
+ ```bash
57
+ shakil-stack build
58
+ ```
28
59
 
60
+ ### 4. Prisma Power Tools
61
+ Manage your database without leaving the CLI:
29
62
  ```bash
30
- shakil-stack my-awesome-project
63
+ shakil-stack prisma generate # Update Prisma Client
64
+ shakil-stack prisma migrate # Apply migrations to DB
31
65
  ```
32
66
 
67
+ ---
68
+
33
69
  ## 📂 Project Structure
34
70
 
35
71
  ```text
36
- my-awesome-project/
72
+ my-awesome-app/
37
73
  ├── backend/
38
- │ ├── prisma/
39
- │ │ └── schema.prisma (Better Auth & Prisma 7 ready)
74
+ │ ├── prisma/ # Schema & Config
40
75
  │ ├── src/
41
- │ │ ├── server.ts
42
- │ │ └── app/ (EchoNet logic)
43
- └── .env
44
- ├── frontend/ (Next.js App)
76
+ │ │ ├── server.ts # Entry point
77
+ │ │ └── app/ # Core logic
78
+ │ ├── module/ # Feature-based modules
79
+ │ │ ├── middleware/ # Security & Global handlers
80
+ │ │ └── utils/ # Reusable helpers
81
+ │ └── tsconfig.json
82
+ ├── frontend/ (Next.js)
45
83
  │ ├── src/
46
- │ │ ├── app/
47
- │ │ ├── components/
48
- │ │ └── ...
84
+ │ │ ├── app/ # Routes & Pages
85
+ │ │ ├── components/ # UI Components
86
+ │ │ └── services/ # API integration
49
87
  └── README.md
50
88
  ```
51
89
 
52
- ## 🏗️ Post-Installation Steps
53
-
54
- After the generator finishes, follow these steps to start your development:
55
-
56
- 1. **Configure Database**: Update the `DATABASE_URL` in `backend/.env`.
57
- 2. **Start Backend**:
58
- ```bash
59
- cd backend
60
- pnpm dev # or npm run dev
61
- ```
62
- 3. **Start Frontend**:
63
- ```bash
64
- cd frontend
65
- pnpm dev # or npm run dev
66
- ```
90
+ ---
67
91
 
68
- ## 📜 Commands (Backend)
92
+ ## 🛠️ Post-Setup Checklist
93
+ 1. **Environment**: Update `backend/.env` with your `DATABASE_URL`.
94
+ 2. **Database**: Run `shakil-stack prisma migrate` to setup your tables.
95
+ 3. **Launch**: Run `npm dev` in both folders.
69
96
 
70
- - `pnpm dev`: Starts the server with `tsx` and `nodemon`.
71
- - `pnpm build`: Builds the project using `tsup`.
72
- - `pnpm start`: Runs the built project from `dist/`.
97
+ ---
73
98
 
74
99
  ## 🤝 Contributing
100
+ Contributions make the open-source community an amazing place to learn, inspire, and create.
101
+ 1. Fork the Project.
102
+ 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`).
103
+ 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`).
104
+ 4. Push to the Branch (`git push origin feature/AmazingFeature`).
105
+ 5. Open a Pull Request.
106
+
107
+ Please read our [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) before contributing.
75
108
 
76
- Feel free to open issues or submit pull requests to improve the Shakil-Stack generator!
109
+ ## 📄 License
110
+ Distributed under the MIT License. See `LICENSE` for more information.
77
111
 
78
112
  ---
79
- Developed with by **Shakil Ahmed Billal**
113
+ Built with by **Shakil Ahmed Billal**
package/bin/index.js CHANGED
@@ -3,11 +3,30 @@
3
3
  const fs = require('fs-extra');
4
4
  const path = require('path');
5
5
  const { execSync } = require('child_process');
6
+ const { Command } = require('commander');
6
7
  const inquirer = require('inquirer');
7
8
  const chalk = require('chalk');
8
9
  const ora = require('ora');
9
10
 
10
- async function main() {
11
+ const program = new Command();
12
+
13
+ // --- Utils ---
14
+ const getPackageManager = () => {
15
+ if (fs.existsSync('pnpm-lock.yaml')) return 'pnpm';
16
+ if (fs.existsSync('yarn.lock')) return 'yarn';
17
+ return 'npm';
18
+ };
19
+
20
+ const runCommand = (command, cwd = process.cwd()) => {
21
+ try {
22
+ execSync(command, { stdio: 'inherit', cwd });
23
+ } catch (err) {
24
+ // console.error(chalk.red(`Failed to execute: ${command}`));
25
+ }
26
+ };
27
+
28
+ // --- Command: Init ---
29
+ const initProject = async (name) => {
11
30
  console.log(chalk.cyan('\n🚀 Initializing Shakil-Stack Project Generator...\n'));
12
31
 
13
32
  const answers = await inquirer.prompt([
@@ -15,7 +34,7 @@ async function main() {
15
34
  type: 'input',
16
35
  name: 'projectName',
17
36
  message: 'What is your project name?',
18
- default: 'my-new-project',
37
+ default: name || 'my-new-project',
19
38
  validate: (input) => (input ? true : 'Project name is required'),
20
39
  },
21
40
  {
@@ -42,12 +61,10 @@ async function main() {
42
61
  }
43
62
 
44
63
  try {
45
- // 1. Create Root Directory
46
64
  await fs.ensureDir(projectPath);
47
-
48
65
  const spinner = ora(`🚀 Creating project: ${chalk.cyan(projectName)}...`).start();
49
66
 
50
- // 2. Define Backend Folder Structure
67
+ // Backend Folder Structure
51
68
  const backendDirs = [
52
69
  'prisma',
53
70
  'src/app/config',
@@ -65,11 +82,9 @@ async function main() {
65
82
  await fs.ensureDir(path.join(projectPath, 'backend', dir));
66
83
  }
67
84
 
68
- // 3. Generate Frontend using create-next-app FIRST
85
+ // Frontend (create-next-app)
69
86
  spinner.text = `📦 Running create-next-app for frontend...`;
70
87
  spinner.stop();
71
-
72
- // We run create-next-app in the project root to create the 'frontend' folder
73
88
  const nextAppCmd = `npx create-next-app@latest frontend --typescript --tailwind --eslint --app --src-dir --import-alias "@/*" --use-${packageManager} --no-git`;
74
89
  try {
75
90
  execSync(nextAppCmd, { cwd: projectPath, stdio: 'inherit' });
@@ -78,7 +93,7 @@ async function main() {
78
93
  await fs.ensureDir(path.join(projectPath, 'frontend'));
79
94
  }
80
95
 
81
- // 4. Create additional frontend folders AFTER create-next-app
96
+ // Frontend extra folders
82
97
  const frontendExtraFolders = ['config', 'hooks', 'lib', 'services', 'types'];
83
98
  for (const folder of frontendExtraFolders) {
84
99
  await fs.ensureDir(path.join(projectPath, 'frontend', 'src', folder));
@@ -86,13 +101,12 @@ async function main() {
86
101
 
87
102
  spinner.start(`📂 Finalizing root files and backend code...`);
88
103
 
89
- // 5. Root Files
104
+ // Root Files
90
105
  await fs.outputFile(path.join(projectPath, '.env'), 'DATABASE_URL="postgresql://user:password@localhost:5432/mydb"\nPORT=8000\nNODE_ENV=development\nJWT_SECRET="your-secret-key"');
91
106
  await fs.outputFile(path.join(projectPath, '.gitignore'), 'node_modules\n.env\ndist\n*.db\n.next\n.DS_Store');
92
107
  await fs.outputFile(path.join(projectPath, 'README.md'), `# ${projectName}\n\nGenerated with Full Shakil-Stack CLI.`);
93
108
 
94
- // 6. Backend Files (Complete EchoNet Clone)
95
-
109
+ // Backend Files Templates
96
110
  const serverTs = `import { Server } from 'http';
97
111
  import app from './app.js';
98
112
  import config from './app/config/index.js';
@@ -379,7 +393,33 @@ export default defineConfig({
379
393
  }
380
394
  `;
381
395
 
382
- // Write backend files
396
+ const sendResponseTs = `import { Response } from 'express';
397
+
398
+ type IResponse<T> = {
399
+ statusCode: number;
400
+ success: boolean;
401
+ message?: string | null;
402
+ meta?: {
403
+ limit: number;
404
+ page: number;
405
+ total: number;
406
+ };
407
+ data: T;
408
+ };
409
+
410
+ const sendResponse = <T>(res: Response, data: IResponse<T>) => {
411
+ res.status(data.statusCode).json({
412
+ success: data.success,
413
+ message: data.message || null,
414
+ meta: data.meta || null,
415
+ data: data.data || null,
416
+ });
417
+ };
418
+
419
+ export default sendResponse;
420
+ `;
421
+
422
+ // Writing Backend Files
383
423
  await fs.outputFile(path.join(projectPath, 'backend', 'src', 'server.ts'), serverTs);
384
424
  await fs.outputFile(path.join(projectPath, 'backend', 'src', 'app.ts'), appTs);
385
425
  await fs.outputFile(path.join(projectPath, 'backend', 'src', 'app', 'config', 'index.ts'), configTs);
@@ -390,6 +430,7 @@ export default defineConfig({
390
430
  await fs.outputFile(path.join(projectPath, 'backend', 'src', 'app', 'middleware', 'notFound.ts'), notFoundTs);
391
431
  await fs.outputFile(path.join(projectPath, 'backend', 'src', 'app', 'middleware', 'sanitizeRequest.ts'), sanitizeRequestTs);
392
432
  await fs.outputFile(path.join(projectPath, 'backend', 'src', 'app', 'utils', 'catchAsync.ts'), catchAsyncTs);
433
+ await fs.outputFile(path.join(projectPath, 'backend', 'src', 'app', 'utils', 'sendResponse.ts'), sendResponseTs);
393
434
  await fs.outputFile(path.join(projectPath, 'backend', 'src', 'app', 'utils', 'sanitizer.ts'), sanitizerTs);
394
435
  await fs.outputFile(path.join(projectPath, 'backend', 'src', 'app', 'errorHelpers', 'ApiError.ts'), apiErrorTs);
395
436
  await fs.outputFile(path.join(projectPath, 'backend', 'prisma', 'schema.prisma'), schemaPrisma);
@@ -398,7 +439,6 @@ export default defineConfig({
398
439
  await fs.outputFile(path.join(projectPath, 'backend', '.gitignore'), 'node_modules\ndist\n.env');
399
440
  await fs.outputFile(path.join(projectPath, 'backend', '.env'), 'DATABASE_URL="postgresql://user:password@localhost:5432/mydb"\nJWT_SECRET="your-secret-key"');
400
441
 
401
- // Backend package.json
402
442
  const backendPkg = {
403
443
  name: `${projectName}-backend`,
404
444
  version: '1.0.0',
@@ -446,15 +486,9 @@ export default defineConfig({
446
486
 
447
487
  spinner.succeed(chalk.green(`✅ Project structure created! ✨`));
448
488
 
449
- // 7. Dependency Installation
450
489
  if (installDeps) {
451
490
  console.log(chalk.yellow(`\n📦 Finalizing dependencies with ${packageManager}...\n`));
452
- try {
453
- execSync(`cd "${path.join(projectPath, 'backend')}" && ${packageManager} install`, { stdio: 'inherit' });
454
- console.log(chalk.green(`\n✅ Backend dependencies installed! ✨\n`));
455
- } catch (err) {
456
- console.log(chalk.red(`\n❌ Step failed. You can manually run '${packageManager} install' in the backend folder.\n`));
457
- }
491
+ runCommand(`cd "${path.join(projectPath, 'backend')}" && ${packageManager} install`);
458
492
  }
459
493
 
460
494
  console.log(chalk.cyan(`To get started:`));
@@ -466,6 +500,170 @@ export default defineConfig({
466
500
  console.error(error);
467
501
  process.exit(1);
468
502
  }
469
- }
503
+ };
504
+
505
+ // --- Command: Generate Module ---
506
+ const generateModule = async (name) => {
507
+ if (!name) {
508
+ console.log(chalk.red('❌ Error: Module name is required.'));
509
+ process.exit(1);
510
+ }
470
511
 
471
- main();
512
+ const moduleName = name.charAt(0).toUpperCase() + name.slice(1);
513
+ const lowercaseName = name.toLowerCase();
514
+
515
+ // Check if inside a shakil-stack project
516
+ const backendRoot = fs.existsSync('backend') ? 'backend' : '.';
517
+ const moduleDir = path.join(backendRoot, 'src', 'app', 'module', moduleName);
518
+
519
+ if (!fs.existsSync(path.join(backendRoot, 'src', 'app', 'module'))) {
520
+ console.log(chalk.red('❌ Error: This command must be run inside your shakil-stack project root or backend directory.'));
521
+ process.exit(1);
522
+ }
523
+
524
+ if (fs.existsSync(moduleDir)) {
525
+ console.log(chalk.red(`❌ Error: Module ${moduleName} already exists.`));
526
+ process.exit(1);
527
+ }
528
+
529
+ const spinner = ora(`🛠️ Generating module: ${chalk.cyan(moduleName)}...`).start();
530
+
531
+ try {
532
+ await fs.ensureDir(moduleDir);
533
+
534
+ const files = {
535
+ 'controller.ts': `import { Request, Response } from 'express';
536
+ import httpStatus from 'http-status';
537
+ import catchAsync from '../../utils/catchAsync.js';
538
+ import sendResponse from '../../utils/sendResponse.js';
539
+ import { ${moduleName}Service } from './${lowercaseName}.service.js';
540
+
541
+ const create${moduleName} = catchAsync(async (req: Request, res: Response) => {
542
+ const result = await ${moduleName}Service.create${moduleName}IntoDB(req.body);
543
+ sendResponse(res, {
544
+ statusCode: httpStatus.OK,
545
+ success: true,
546
+ message: '${moduleName} created successfully',
547
+ data: result,
548
+ });
549
+ });
550
+
551
+ export const ${moduleName}Controller = {
552
+ create${moduleName},
553
+ };
554
+ `,
555
+ 'service.ts': `import { ${moduleName} } from '@prisma/client';
556
+ import prisma from '../../lib/prisma.js';
557
+
558
+ const create${moduleName}IntoDB = async (payload: any) => {
559
+ // Logic here
560
+ return payload;
561
+ };
562
+
563
+ export const ${moduleName}Service = {
564
+ create${moduleName}IntoDB,
565
+ };
566
+ `,
567
+ 'route.ts': `import { Router } from 'express';
568
+ import { ${moduleName}Controller } from './${lowercaseName}.controller.js';
569
+
570
+ const router = Router();
571
+
572
+ router.post('/create-${lowercaseName}', ${moduleName}Controller.create${moduleName});
573
+
574
+ export const ${moduleName}Routes = router;
575
+ `,
576
+ 'interface.ts': `export type I${moduleName} = {
577
+ // Define interface
578
+ };
579
+ `,
580
+ 'validation.ts': `import { z } from 'zod';
581
+
582
+ const create${moduleName}ValidationSchema = z.object({
583
+ body: z.object({
584
+ // Define schema
585
+ }),
586
+ });
587
+
588
+ export const ${moduleName}Validations = {
589
+ create${moduleName}ValidationSchema,
590
+ };
591
+ `,
592
+ 'constant.ts': `export const ${moduleName}SearchableFields = [];
593
+ `,
594
+ };
595
+
596
+ for (const [ext, content] of Object.entries(files)) {
597
+ await fs.outputFile(path.join(moduleDir, `${lowercaseName}.${ext}`), content);
598
+ }
599
+
600
+ spinner.succeed(chalk.green(`✅ Module ${moduleName} generated successfully! ✨`));
601
+ console.log(chalk.gray(`Created at: ${moduleDir}`));
602
+
603
+ } catch (error) {
604
+ spinner.fail(chalk.red('❌ Failed to generate module.'));
605
+ console.error(error);
606
+ }
607
+ };
608
+
609
+ // --- CLI Structure ---
610
+ program
611
+ .name('shakil-stack')
612
+ .description('Full-stack EchoNet-style project generator CLI')
613
+ .version('1.0.0');
614
+
615
+ program
616
+ .command('init')
617
+ .description('Initialize a new full-stack project')
618
+ .argument('[projectName]', 'Name of the project')
619
+ .action((projectName) => {
620
+ initProject(projectName);
621
+ });
622
+
623
+ program
624
+ .command('generate')
625
+ .alias('g')
626
+ .description('Generate a new module')
627
+ .argument('<type>', 'Type of generation (module)')
628
+ .argument('<name>', 'Name of the module')
629
+ .action((type, name) => {
630
+ if (type === 'module') {
631
+ generateModule(name);
632
+ } else {
633
+ console.log(chalk.red(`❌ Error: Unknown generation type: ${type}`));
634
+ }
635
+ });
636
+
637
+ program
638
+ .command('build')
639
+ .description('Build the backend for production')
640
+ .action(() => {
641
+ const pm = getPackageManager();
642
+ const backendRoot = fs.existsSync('backend') ? 'backend' : '.';
643
+ console.log(chalk.cyan(`🏗️ Building backend with ${pm}...`));
644
+ runCommand(`${pm} run build`, backendRoot);
645
+ });
646
+
647
+ program
648
+ .command('prisma')
649
+ .description('Prisma utilities')
650
+ .argument('<subcommand>', 'generate | migrate')
651
+ .action((subcommand) => {
652
+ const backendRoot = fs.existsSync('backend') ? 'backend' : '.';
653
+ if (subcommand === 'generate') {
654
+ console.log(chalk.cyan('🔄 Generating Prisma client...'));
655
+ runCommand('npx prisma generate', backendRoot);
656
+ } else if (subcommand === 'migrate') {
657
+ console.log(chalk.cyan('🚀 Running Prisma migrations...'));
658
+ runCommand('npx prisma migrate dev', backendRoot);
659
+ } else {
660
+ console.log(chalk.red(`❌ Error: Unknown prisma subcommand: ${subcommand}`));
661
+ }
662
+ });
663
+
664
+ // Handle default action (no command)
665
+ if (!process.argv.slice(2).length) {
666
+ initProject();
667
+ } else {
668
+ program.parse(process.argv);
669
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shakil-dev/shakil-stack",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Full-stack EchoNet-style project generator CLI",
5
5
  "main": "./bin/index.js",
6
6
  "bin": {