@shakil-dev/shakil-stack 2.2.5 → 2.2.6

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 (2) hide show
  1. package/dist/index.js +16 -17
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{Command as le}from"commander";import te from"fs-extra";import T from"path";import{fileURLToPath as ue}from"url";import s from"fs-extra";import o from"path";import n from"chalk";import ae from"ora";import _ from"inquirer";import{execSync as oe}from"child_process";import xe from"fs-extra";var i=(e,r=process.cwd())=>{try{return oe(e,{stdio:"inherit",cwd:r}),!0}catch{return!1}},h=()=>{let e=process.env.npm_config_user_agent||"";return e.includes("pnpm")?"pnpm":e.includes("yarn")?"yarn":"npm"};var k=e=>`import { Server } from 'http';
2
+ import{Command as le}from"commander";import te from"fs-extra";import T from"path";import{fileURLToPath as me}from"url";import s from"fs-extra";import r from"path";import n from"chalk";import ne from"ora";import _ from"inquirer";import{execSync as oe}from"child_process";import ye from"fs-extra";var i=(e,o=process.cwd())=>{try{return oe(e,{stdio:"inherit",cwd:o}),!0}catch{return!1}},f=()=>{let e=process.env.npm_config_user_agent||"";return e.includes("pnpm")?"pnpm":e.includes("yarn")?"yarn":"npm"};var k=e=>`import { Server } from 'http';
3
3
  import app from './app.js';
4
4
  import config from './app/config/index.js';
5
5
 
@@ -205,7 +205,6 @@ const sendResponse = <T>(res: Response, data: IResponse<T>) => {
205
205
  export default sendResponse;
206
206
  `,$=`generator client {
207
207
  provider = "prisma-client-js"
208
- previewFeatures = ["prismaSchemaFolder"]
209
208
  output = "../../generated/prisma"
210
209
  }
211
210
 
@@ -407,23 +406,23 @@ ${e}/
407
406
 
408
407
  ---
409
408
  Built with \u26A1 by **Shakil Ahmed Billal**
410
- `;var x=async e=>{let r=e;r||(r=(await _.prompt([{type:"input",name:"projectName",message:"What is your project name?",default:"shakil-stack-app"}])).projectName),r||(console.log(n.red("\u274C Error: Project name is required.")),process.exit(1));let{packageManager:a,useShadcn:g,installDeps:c}=await _.prompt([{type:"list",name:"packageManager",message:"Which package manager do you want to use?",choices:["pnpm","npm","yarn"],default:h()},{type:"confirm",name:"useShadcn",message:"Would you like to use shadcn/ui?",default:!0},{type:"confirm",name:"installDeps",message:"Do you want to install dependencies automatically?",default:!0}]),t=o.join(process.cwd(),r);s.existsSync(t)&&(console.log(n.red(`\u274C Error: Directory ${r} already exists.`)),process.exit(1)),console.log(n.cyan(`
411
- \u{1F680} Initializing ${n.bold(r)}...
412
- `));let d=ae("\u{1F6E0}\uFE0F Creating project structure...").start();try{await s.ensureDir(t),await s.ensureDir(o.join(t,"backend","src","app","config")),await s.ensureDir(o.join(t,"backend","src","app","lib")),await s.ensureDir(o.join(t,"backend","src","app","module")),await s.ensureDir(o.join(t,"backend","src","app","routes")),await s.ensureDir(o.join(t,"backend","src","app","middleware")),await s.ensureDir(o.join(t,"backend","src","app","utils")),await s.ensureDir(o.join(t,"backend","src","app","errorHelpers")),await s.ensureDir(o.join(t,"backend","prisma","schema")),console.log(n.cyan(`
413
- \u{1F5BC}\uFE0F Scaffolding Next.js frontend...`)),i(`npx create-next-app@latest frontend --ts --tailwind --eslint --app --src-dir --import-alias "@/*" --use-${a}`,t);let m=["config","hooks","lib","services","types"];for(let f of m)await s.ensureDir(o.join(t,"frontend","src",f));if(g){console.log(n.cyan(`
414
- \u{1F3A8} Setting up shadcn/ui...`));try{i("npx shadcn@latest init -d",o.join(t,"frontend")),console.log(n.cyan("\u{1F4E6} Adding common shadcn/ui components...")),i(`npx shadcn@latest add ${["button","card","input","label","textarea","dialog","dropdown-menu","table","tabs","checkbox"].join(" ")} -y`,o.join(t,"frontend")),console.log(n.green("\u2705 shadcn/ui and common components initialized successfully!\u2728"))}catch{console.log(n.yellow(`
415
- \u26A0\uFE0F Warning: Failed to automate shadcn/ui init. You can run "npx shadcn@latest init" in the frontend folder.`))}}await s.outputFile(o.join(t,"backend","src","server.ts"),k(r)),await s.outputFile(o.join(t,"backend","src","app.ts"),j(r)),await s.outputFile(o.join(t,"backend","src","app","config","index.ts"),v),await s.outputFile(o.join(t,"backend","src","app","lib","prisma.ts"),R),await s.outputFile(o.join(t,"backend","src","app","lib","auth.ts"),S),await s.outputFile(o.join(t,"backend","src","app","routes","index.ts"),E),await s.outputFile(o.join(t,"backend","src","app","middleware","globalErrorHandler.ts"),A),await s.outputFile(o.join(t,"backend","src","app","middleware","notFound.ts"),C),await s.outputFile(o.join(t,"backend","src","app","middleware","sanitizeRequest.ts"),P),await s.outputFile(o.join(t,"backend","src","app","utils","catchAsync.ts"),D),await s.outputFile(o.join(t,"backend","src","app","utils","sendResponse.ts"),I),await s.outputFile(o.join(t,"backend","src","app","utils","sanitizer.ts"),O),await s.outputFile(o.join(t,"backend","src","app","errorHelpers","ApiError.ts"),F),await s.outputFile(o.join(t,"backend","prisma","schema","schema.prisma"),$),await s.outputFile(o.join(t,"backend","prisma","schema","auth.prisma"),N);let y=["meal.prisma","order.prisma","provider.prisma","review.prisma"];for(let f of y)await s.outputFile(o.join(t,"backend","prisma","schema",f),"// ${schema.split('.')[0].charAt(0).toUpperCase() + schema.split('.')[0].slice(1)} model\n");await s.outputFile(o.join(t,"backend","prisma.config.ts"),q),await s.outputFile(o.join(t,"backend","tsconfig.json"),H),await s.outputFile(o.join(t,".gitignore"),M),await s.outputFile(o.join(t,"LICENSE"),L),await s.outputFile(o.join(t,"README.md"),U(r)),await s.outputFile(o.join(t,"CODE_OF_CONDUCT.md"),z),await s.outputFile(o.join(t,".env"),`DATABASE_URL="postgresql://postgres:postgres@localhost:5432/${r}"
409
+ `;var x=async e=>{let o=e;o||(o=(await _.prompt([{type:"input",name:"projectName",message:"What is your project name?",default:"shakil-stack-app"}])).projectName),o||(console.log(n.red("\u274C Error: Project name is required.")),process.exit(1));let{packageManager:a,useShadcn:g,installDeps:c}=await _.prompt([{type:"list",name:"packageManager",message:"Which package manager do you want to use?",choices:["pnpm","npm","yarn"],default:f()},{type:"confirm",name:"useShadcn",message:"Would you like to use shadcn/ui?",default:!0},{type:"confirm",name:"installDeps",message:"Do you want to install dependencies automatically?",default:!0}]),t=r.join(process.cwd(),o);s.existsSync(t)&&(console.log(n.red(`\u274C Error: Directory ${o} already exists.`)),process.exit(1)),console.log(n.cyan(`
410
+ \u{1F680} Initializing ${n.bold(o)}...
411
+ `));let d=ne("\u{1F6E0}\uFE0F Creating project structure...").start();try{await s.ensureDir(t),await s.ensureDir(r.join(t,"backend","src","app","config")),await s.ensureDir(r.join(t,"backend","src","app","lib")),await s.ensureDir(r.join(t,"backend","src","app","module")),await s.ensureDir(r.join(t,"backend","src","app","routes")),await s.ensureDir(r.join(t,"backend","src","app","middleware")),await s.ensureDir(r.join(t,"backend","src","app","utils")),await s.ensureDir(r.join(t,"backend","src","app","errorHelpers")),await s.ensureDir(r.join(t,"backend","prisma","schema")),console.log(n.cyan(`
412
+ \u{1F5BC}\uFE0F Scaffolding Next.js frontend...`)),i(`npx create-next-app@latest frontend --ts --tailwind --eslint --app --src-dir --import-alias "@/*" --use-${a}`,t);let l=["config","hooks","lib","services","types"];for(let y of l)await s.ensureDir(r.join(t,"frontend","src",y));if(g){console.log(n.cyan(`
413
+ \u{1F3A8} Setting up shadcn/ui...`));try{i("npx shadcn@latest init -d",r.join(t,"frontend")),console.log(n.cyan("\u{1F4E6} Adding common shadcn/ui components...")),i(`npx shadcn@latest add ${["button","card","input","label","textarea","dialog","dropdown-menu","table","tabs","checkbox"].join(" ")} -y`,r.join(t,"frontend")),console.log(n.green("\u2705 shadcn/ui and common components initialized successfully!\u2728"))}catch{console.log(n.yellow(`
414
+ \u26A0\uFE0F Warning: Failed to automate shadcn/ui init. You can run "npx shadcn@latest init" in the frontend folder.`))}}await s.outputFile(r.join(t,"backend","src","server.ts"),k(o)),await s.outputFile(r.join(t,"backend","src","app.ts"),j(o)),await s.outputFile(r.join(t,"backend","src","app","config","index.ts"),v),await s.outputFile(r.join(t,"backend","src","app","lib","prisma.ts"),R),await s.outputFile(r.join(t,"backend","src","app","lib","auth.ts"),S),await s.outputFile(r.join(t,"backend","src","app","routes","index.ts"),E),await s.outputFile(r.join(t,"backend","src","app","middleware","globalErrorHandler.ts"),A),await s.outputFile(r.join(t,"backend","src","app","middleware","notFound.ts"),C),await s.outputFile(r.join(t,"backend","src","app","middleware","sanitizeRequest.ts"),P),await s.outputFile(r.join(t,"backend","src","app","utils","catchAsync.ts"),D),await s.outputFile(r.join(t,"backend","src","app","utils","sendResponse.ts"),I),await s.outputFile(r.join(t,"backend","src","app","utils","sanitizer.ts"),O),await s.outputFile(r.join(t,"backend","src","app","errorHelpers","ApiError.ts"),F),await s.outputFile(r.join(t,"backend","prisma","schema","schema.prisma"),$),await s.outputFile(r.join(t,"backend","prisma","schema","auth.prisma"),N),await s.outputFile(r.join(t,"backend","prisma.config.ts"),q),await s.outputFile(r.join(t,"backend","tsconfig.json"),H),await s.outputFile(r.join(t,".gitignore"),M),await s.outputFile(r.join(t,"LICENSE"),L),await s.outputFile(r.join(t,"README.md"),U(o)),await s.outputFile(r.join(t,"CODE_OF_CONDUCT.md"),z),await s.outputFile(r.join(t,".env"),`DATABASE_URL="postgresql://postgres:postgres@localhost:5432/${o}"
416
415
  JWT_SECRET="your-secret-key"
417
416
  NODE_ENV="development"
418
- PORT=8000`);let re={name:`${r}-backend`,version:"1.0.0",type:"module",scripts:{test:'echo "Error: no test specified" && exit 1',dev:"nodemon --exec tsx src/server.ts",build:"prisma generate && tsup src/server.ts --format esm --platform node --target node20 --outDir dist --external pg-native",postinstall:"prisma generate",start:"node dist/server.js","prisma:generate":"prisma generate","prisma:migrate":"prisma migrate dev","prisma:studio":"prisma studio",seed:"tsx prisma/seed.ts",setup:"pnpm install && pnpm add @prisma/adapter-pg pg && pnpm add -D @types/pg && pnpm prisma:generate",predev:"pnpm run prisma:generate",init:"pnpm run prisma:generate && pnpm run prisma:migrate --name init",lint:"eslint src/**/*.ts","lint:fix":"eslint src/**/*.ts --fix",format:"prettier --write .",push:"prisma db push",pull:"prisma db pull"},dependencies:{"@prisma/adapter-pg":"^7.5.0","@prisma/client":"^7.5.0","better-auth":"^1.5.6","cookie-parser":"^1.4.7",cors:"^2.8.6",dompurify:"^3.3.3",dotenv:"^17.3.1",express:"^5.2.1","express-rate-limit":"^8.3.1",helmet:"^8.1.0","http-status":"^2.1.0",jsdom:"^29.0.1",jsonwebtoken:"^9.0.3",morgan:"^1.10.1",pg:"^8.20.0",winston:"^3.19.0",zod:"^4.3.6"},devDependencies:{"@types/cookie-parser":"^1.4.10","@types/cors":"^2.8.19","@types/express":"^5.0.6","@types/node":"^20.19.37","@types/pg":"^8.20.0","@types/morgan":"^1.9.10","@types/jsdom":"^21.1.7",prisma:"^7.5.0",tsx:"^4.21.0",nodemon:"^3.1.14",tsup:"^8.5.1",typescript:"^5.9.3",eslint:"^9.21.0",prettier:"^3.5.2"}};await s.writeJson(o.join(t,"backend","package.json"),re,{spaces:2}),d.succeed(n.green("\u2705 Project structure created! \u2728")),c&&(console.log(n.yellow(`
417
+ PORT=8000`);let b={name:`${o}-backend`,version:"1.0.0",type:"module",scripts:{test:'echo "Error: no test specified" && exit 1',dev:"nodemon --exec tsx src/server.ts",build:"prisma generate && tsup src/server.ts --format esm --platform node --target node20 --outDir dist --external pg-native",postinstall:"prisma generate",start:"node dist/server.js","prisma:generate":"prisma generate","prisma:migrate":"prisma migrate dev","prisma:studio":"prisma studio",seed:"tsx prisma/seed.ts",setup:"pnpm install && pnpm add @prisma/adapter-pg pg && pnpm add -D @types/pg && pnpm prisma:generate",predev:"pnpm run prisma:generate",init:"pnpm run prisma:generate && pnpm run prisma:migrate --name init",lint:"eslint src/**/*.ts","lint:fix":"eslint src/**/*.ts --fix",format:"prettier --write .",push:"prisma db push",pull:"prisma db pull"},dependencies:{"@prisma/adapter-pg":"^7.5.0","@prisma/client":"^7.5.0","better-auth":"^1.5.6","cookie-parser":"^1.4.7",cors:"^2.8.6",dompurify:"^3.3.3",dotenv:"^17.3.1",express:"^5.2.1","express-rate-limit":"^8.3.1",helmet:"^8.1.0","http-status":"^2.1.0",jsdom:"^29.0.1",jsonwebtoken:"^9.0.3",morgan:"^1.10.1",pg:"^8.20.0",winston:"^3.19.0",zod:"^4.3.6"},devDependencies:{"@types/cookie-parser":"^1.4.10","@types/cors":"^2.8.19","@types/express":"^5.0.6","@types/node":"^20.19.37","@types/pg":"^8.20.0","@types/morgan":"^1.9.10","@types/jsdom":"^21.1.7",prisma:"^7.5.0",tsx:"^4.21.0",nodemon:"^3.1.14",tsup:"^8.5.1",typescript:"^5.9.3",eslint:"^9.21.0",prettier:"^3.5.2"}};await s.writeJson(r.join(t,"backend","package.json"),b,{spaces:2}),d.succeed(n.green("\u2705 Project structure created! \u2728")),c&&(console.log(n.yellow(`
419
418
  \u{1F4E6} Finalizing dependencies with ${a}...
420
- `)),i(`${a} install`,o.join(t,"backend"))),console.log(n.cyan("To get started:")),console.log(n.white(` cd ${r}`)),console.log(n.white(` cd backend && ${a} dev
419
+ `)),i(`${a} install`,r.join(t,"backend"))),console.log(n.cyan("To get started:")),console.log(n.white(` cd ${o}`)),console.log(n.white(` cd backend && ${a} dev
421
420
  `)),console.log(n.white(` cd frontend && ${a} dev
422
- `))}catch(m){d.fail(n.red("\u274C Failed to initialize project.")),console.error(m),process.exit(1)}};import l from"fs-extra";import b from"path";import p from"chalk";import pe from"ora";var B=(e,r)=>`import { Request, Response } from 'express';
421
+ `))}catch(l){d.fail(n.red("\u274C Failed to initialize project.")),console.error(l),process.exit(1)}};import m from"fs-extra";import h from"path";import p from"chalk";import ie from"ora";var B=(e,o)=>`import { Request, Response } from 'express';
423
422
  import httpStatus from 'http-status';
424
423
  import catchAsync from '../../utils/catchAsync.js';
425
424
  import sendResponse from '../../utils/sendResponse.js';
426
- import { ${e}Service } from './${r}.service.js';
425
+ import { ${e}Service } from './${o}.service.js';
427
426
 
428
427
  const create${e} = catchAsync(async (req: Request, res: Response) => {
429
428
  const result = await ${e}Service.create${e}IntoDB(req.body);
@@ -438,7 +437,7 @@ const create${e} = catchAsync(async (req: Request, res: Response) => {
438
437
  export const ${e}Controller = {
439
438
  create${e},
440
439
  };
441
- `,W=(e,r)=>`import { ${e} } from '@prisma/client';
440
+ `,W=(e,o)=>`import { ${e} } from '@prisma/client';
442
441
  import prisma from '../../lib/prisma.js';
443
442
 
444
443
  const create${e}IntoDB = async (payload: any) => {
@@ -449,12 +448,12 @@ const create${e}IntoDB = async (payload: any) => {
449
448
  export const ${e}Service = {
450
449
  create${e}IntoDB,
451
450
  };
452
- `,G=(e,r)=>`import { Router } from 'express';
453
- import { ${e}Controller } from './${r}.controller.js';
451
+ `,G=(e,o)=>`import { Router } from 'express';
452
+ import { ${e}Controller } from './${o}.controller.js';
454
453
 
455
454
  const router = Router();
456
455
 
457
- router.post('/create-${r}', ${e}Controller.create${e});
456
+ router.post('/create-${o}', ${e}Controller.create${e});
458
457
 
459
458
  export const ${e}Routes = router;
460
459
  `,V=e=>`export type I${e} = {
@@ -478,4 +477,4 @@ export const ${e}Validations = {
478
477
  createdAt DateTime @default(now())
479
478
  updatedAt DateTime @updatedAt
480
479
  }
481
- `;var X=async e=>{e||(console.log(p.red("\u274C Error: Module name is required.")),process.exit(1));let r=e.charAt(0).toUpperCase()+e.slice(1),a=e.toLowerCase(),g=l.existsSync("backend")?"backend":".",c=b.join(g,"src","app","module",r);l.existsSync(b.join(g,"src","app","module"))||(console.log(p.red("\u274C Error: This command must be run inside your shakil-stack project root or backend directory.")),process.exit(1)),l.existsSync(c)&&(console.log(p.red(`\u274C Error: Module ${r} already exists.`)),process.exit(1));let t=pe(`\u{1F6E0}\uFE0F Generating module: ${p.cyan(r)}...`).start();try{await l.ensureDir(c);let d={"controller.ts":B(r,a),"service.ts":W(r,a),"route.ts":G(r,a),"interface.ts":V(r),"validation.ts":J(r),"constant.ts":Y(r)};await l.outputFile(b.join(g,"prisma","schema",`${a}.prisma`),K(r));for(let[m,y]of Object.entries(d))await l.outputFile(b.join(c,`${a}.${m}`),y);t.succeed(p.green(`\u2705 Module ${r} generated successfully! \u2728`)),console.log(p.gray(`Created at: ${c}`))}catch(d){t.fail(p.red("\u274C Failed to generate module.")),console.error(d)}};import ce from"fs-extra";import de from"chalk";var Q=async()=>{let e=h(),r=ce.existsSync("backend")?"backend":".";console.log(de.cyan(`\u{1F3D7}\uFE0F Building backend with ${e}...`)),i(`${e} run build`,r)};import me from"fs-extra";import w from"chalk";var Z=async e=>{let r=me.existsSync("backend")?"backend":".";e==="generate"?(console.log(w.cyan("\u{1F504} Generating Prisma client...")),i("npx prisma generate",r)):e==="migrate"?(console.log(w.cyan("\u{1F680} Running Prisma migrations...")),i("npx prisma migrate dev",r)):console.log(w.red(`\u274C Error: Unknown prisma subcommand: ${e}`))};var ge=ue(import.meta.url),ee=T.dirname(ge),fe=T.resolve(ee,te.existsSync(T.resolve(ee,"../../package.json"))?"../../package.json":"../package.json"),he=te.readJsonSync(fe),u=new le;u.name("shakil-stack").description("Full-stack EchoNet-style project generator CLI").version(he.version);u.command("init").description("Initialize a new full-stack project").argument("[projectName]","Name of the project").action(e=>{x(e)});u.command("generate").alias("g").description("Generate a new module").argument("<type>","Type of generation (module)").argument("<name>","Name of the module").action((e,r)=>{e==="module"?X(r):console.log(`\u274C Error: Unknown generation type: ${e}`)});u.command("build").description("Build the backend for production").action(()=>{Q()});u.command("prisma").description("Prisma utilities").argument("<subcommand>","generate | migrate").action(e=>{Z(e)});process.argv.slice(2).length?u.parse(process.argv):x();
480
+ `;var X=async e=>{e||(console.log(p.red("\u274C Error: Module name is required.")),process.exit(1));let o=e.charAt(0).toUpperCase()+e.slice(1),a=e.toLowerCase(),g=m.existsSync("backend")?"backend":".",c=h.join(g,"src","app","module",o);m.existsSync(h.join(g,"src","app","module"))||(console.log(p.red("\u274C Error: This command must be run inside your shakil-stack project root or backend directory.")),process.exit(1)),m.existsSync(c)&&(console.log(p.red(`\u274C Error: Module ${o} already exists.`)),process.exit(1));let t=ie(`\u{1F6E0}\uFE0F Generating module: ${p.cyan(o)}...`).start();try{await m.ensureDir(c);let d={"controller.ts":B(o,a),"service.ts":W(o,a),"route.ts":G(o,a),"interface.ts":V(o),"validation.ts":J(o),"constant.ts":Y(o)};await m.outputFile(h.join(g,"prisma","schema",`${a}.prisma`),K(o));for(let[l,b]of Object.entries(d))await m.outputFile(h.join(c,`${a}.${l}`),b);t.succeed(p.green(`\u2705 Module ${o} generated successfully! \u2728`)),console.log(p.gray(`Created at: ${c}`))}catch(d){t.fail(p.red("\u274C Failed to generate module.")),console.error(d)}};import pe from"fs-extra";import ce from"chalk";var Q=async()=>{let e=f(),o=pe.existsSync("backend")?"backend":".";console.log(ce.cyan(`\u{1F3D7}\uFE0F Building backend with ${e}...`)),i(`${e} run build`,o)};import de from"fs-extra";import w from"chalk";var Z=async e=>{let o=de.existsSync("backend")?"backend":".";e==="generate"?(console.log(w.cyan("\u{1F504} Generating Prisma client...")),i("npx prisma generate",o)):e==="migrate"?(console.log(w.cyan("\u{1F680} Running Prisma migrations...")),i("npx prisma migrate dev",o)):console.log(w.red(`\u274C Error: Unknown prisma subcommand: ${e}`))};var ue=me(import.meta.url),ee=T.dirname(ue),ge=T.resolve(ee,te.existsSync(T.resolve(ee,"../../package.json"))?"../../package.json":"../package.json"),fe=te.readJsonSync(ge),u=new le;u.name("shakil-stack").description("Full-stack EchoNet-style project generator CLI").version(fe.version);u.command("init").description("Initialize a new full-stack project").argument("[projectName]","Name of the project").action(e=>{x(e)});u.command("generate").alias("g").description("Generate a new module").argument("<type>","Type of generation (module)").argument("<name>","Name of the module").action((e,o)=>{e==="module"?X(o):console.log(`\u274C Error: Unknown generation type: ${e}`)});u.command("build").description("Build the backend for production").action(()=>{Q()});u.command("prisma").description("Prisma utilities").argument("<subcommand>","generate | migrate").action(e=>{Z(e)});process.argv.slice(2).length?u.parse(process.argv):x();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shakil-dev/shakil-stack",
3
- "version": "2.2.5",
3
+ "version": "2.2.6",
4
4
  "description": "Full-stack EchoNet-style project generator CLI",
5
5
  "keywords": [
6
6
  "shakil-stack",