@forinda/kickjs-cli 0.3.1 → 0.4.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.
package/dist/cli.js CHANGED
@@ -6,10 +6,13 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
6
6
  import { Command } from "commander";
7
7
 
8
8
  // src/commands/init.ts
9
- import { resolve } from "path";
9
+ import { resolve, basename } from "path";
10
+ import { createInterface } from "readline";
11
+ import { existsSync, readdirSync, rmSync } from "fs";
10
12
 
11
13
  // src/generators/project.ts
12
14
  import { join } from "path";
15
+ import { execSync } from "child_process";
13
16
 
14
17
  // src/utils/fs.ts
15
18
  import { writeFile, mkdir, access, readFile } from "fs/promises";
@@ -171,6 +174,37 @@ bootstrap({
171
174
  await writeFileSafe(join(dir, "src/modules/index.ts"), `import type { AppModuleClass } from '@forinda/kickjs-core'
172
175
 
173
176
  export const modules: AppModuleClass[] = []
177
+ `);
178
+ await writeFileSafe(join(dir, "kick.config.ts"), `import { defineConfig } from '@forinda/kickjs-cli'
179
+
180
+ export default defineConfig({
181
+ modulesDir: 'src/modules',
182
+ defaultRepo: 'inmemory',
183
+
184
+ commands: [
185
+ {
186
+ name: 'test',
187
+ description: 'Run tests with Vitest',
188
+ steps: 'npx vitest run',
189
+ },
190
+ {
191
+ name: 'format',
192
+ description: 'Format code with Prettier',
193
+ steps: 'npx prettier --write src/',
194
+ },
195
+ {
196
+ name: 'format:check',
197
+ description: 'Check formatting without writing',
198
+ steps: 'npx prettier --check src/',
199
+ },
200
+ {
201
+ name: 'check',
202
+ description: 'Run typecheck + format check',
203
+ steps: ['npx tsc --noEmit', 'npx prettier --check src/'],
204
+ aliases: ['verify', 'ci'],
205
+ },
206
+ ],
207
+ })
174
208
  `);
175
209
  await writeFileSafe(join(dir, "vitest.config.ts"), `import { defineConfig } from 'vitest/config'
176
210
  import swc from 'unplugin-swc'
@@ -184,13 +218,48 @@ export default defineConfig({
184
218
  },
185
219
  })
186
220
  `);
187
- console.log(" Project scaffolded successfully!");
221
+ if (options.initGit) {
222
+ try {
223
+ execSync("git init", {
224
+ cwd: dir,
225
+ stdio: "pipe"
226
+ });
227
+ execSync("git add -A", {
228
+ cwd: dir,
229
+ stdio: "pipe"
230
+ });
231
+ execSync('git commit -m "chore: initial commit from kick new"', {
232
+ cwd: dir,
233
+ stdio: "pipe"
234
+ });
235
+ console.log(" Git repository initialized");
236
+ } catch {
237
+ console.log(" Warning: git init failed (git may not be installed)");
238
+ }
239
+ }
240
+ if (options.installDeps) {
241
+ console.log(`
242
+ Installing dependencies with ${packageManager}...
243
+ `);
244
+ try {
245
+ execSync(`${packageManager} install`, {
246
+ cwd: dir,
247
+ stdio: "inherit"
248
+ });
249
+ console.log("\n Dependencies installed successfully!");
250
+ } catch {
251
+ console.log(`
252
+ Warning: ${packageManager} install failed. Run it manually.`);
253
+ }
254
+ }
255
+ console.log("\n Project scaffolded successfully!");
188
256
  console.log();
257
+ const needsCd = dir !== process.cwd();
189
258
  console.log(" Next steps:");
190
- console.log(` cd ${name}`);
191
- console.log(` ${packageManager} install`);
192
- console.log(` kick g module user`);
193
- console.log(` kick dev`);
259
+ if (needsCd) console.log(` cd ${name}`);
260
+ if (!options.installDeps) console.log(` ${packageManager} install`);
261
+ console.log(" kick g module user");
262
+ console.log(" kick dev");
194
263
  console.log();
195
264
  console.log(" Commands:");
196
265
  console.log(" kick dev Start dev server with Vite HMR");
@@ -202,13 +271,107 @@ export default defineConfig({
202
271
  __name(initProject, "initProject");
203
272
 
204
273
  // src/commands/init.ts
274
+ function ask(question, defaultValue) {
275
+ const rl = createInterface({
276
+ input: process.stdin,
277
+ output: process.stdout
278
+ });
279
+ const suffix = defaultValue ? ` (${defaultValue})` : "";
280
+ return new Promise((res) => {
281
+ rl.question(` ${question}${suffix}: `, (answer) => {
282
+ rl.close();
283
+ res(answer.trim() || defaultValue || "");
284
+ });
285
+ });
286
+ }
287
+ __name(ask, "ask");
288
+ async function choose(question, options, defaultIdx = 0) {
289
+ console.log(` ${question}`);
290
+ for (let i = 0; i < options.length; i++) {
291
+ const marker = i === defaultIdx ? ">" : " ";
292
+ console.log(` ${marker} ${i + 1}. ${options[i]}`);
293
+ }
294
+ const answer = await ask("Choose", String(defaultIdx + 1));
295
+ const idx = parseInt(answer, 10) - 1;
296
+ return options[idx] ?? options[defaultIdx];
297
+ }
298
+ __name(choose, "choose");
299
+ async function confirm(question, defaultYes = true) {
300
+ const hint = defaultYes ? "Y/n" : "y/N";
301
+ const answer = await ask(`${question} (${hint})`);
302
+ if (!answer) return defaultYes;
303
+ return answer.toLowerCase().startsWith("y");
304
+ }
305
+ __name(confirm, "confirm");
205
306
  function registerInitCommand(program) {
206
- program.command("new <name>").alias("init").description("Create a new KickJS project").option("-d, --directory <dir>", "Target directory (defaults to project name)").option("--pm <manager>", "Package manager: pnpm | npm | yarn", "pnpm").action(async (name, opts) => {
207
- const directory = resolve(opts.directory || name);
307
+ program.command("new [name]").alias("init").description('Create a new KickJS project (use "." for current directory)').option("-d, --directory <dir>", "Target directory (defaults to project name)").option("--pm <manager>", "Package manager: pnpm | npm | yarn").option("--git", "Initialize git repository").option("--no-git", "Skip git initialization").option("--install", "Install dependencies after scaffolding").option("--no-install", "Skip dependency installation").option("-f, --force", "Remove existing files without prompting").action(async (name, opts) => {
308
+ console.log();
309
+ if (!name) {
310
+ name = await ask("Project name", "my-api");
311
+ }
312
+ let directory;
313
+ if (name === ".") {
314
+ directory = resolve(".");
315
+ name = basename(directory);
316
+ } else {
317
+ directory = resolve(opts.directory || name);
318
+ }
319
+ if (existsSync(directory)) {
320
+ const entries = readdirSync(directory);
321
+ if (entries.length > 0) {
322
+ if (opts.force) {
323
+ console.log(` Clearing existing files in ${directory}...
324
+ `);
325
+ } else {
326
+ console.log(` Directory "${name}" is not empty:`);
327
+ const shown = entries.slice(0, 5);
328
+ for (const entry of shown) {
329
+ console.log(` - ${entry}`);
330
+ }
331
+ if (entries.length > 5) {
332
+ console.log(` ... and ${entries.length - 5} more`);
333
+ }
334
+ console.log();
335
+ const shouldClear = await confirm("Remove all existing files and proceed?", false);
336
+ if (!shouldClear) {
337
+ console.log(" Aborted.\n");
338
+ return;
339
+ }
340
+ }
341
+ for (const entry of entries) {
342
+ rmSync(resolve(directory, entry), {
343
+ recursive: true,
344
+ force: true
345
+ });
346
+ }
347
+ }
348
+ }
349
+ let packageManager = opts.pm;
350
+ if (!packageManager) {
351
+ packageManager = await choose("Package manager:", [
352
+ "pnpm",
353
+ "npm",
354
+ "yarn"
355
+ ], 0);
356
+ }
357
+ let initGit;
358
+ if (opts.git === void 0) {
359
+ initGit = await confirm("Initialize git repository?", true);
360
+ } else {
361
+ initGit = opts.git;
362
+ }
363
+ let installDeps;
364
+ if (opts.install === void 0) {
365
+ installDeps = await confirm("Install dependencies?", true);
366
+ } else {
367
+ installDeps = opts.install;
368
+ }
208
369
  await initProject({
209
370
  name,
210
371
  directory,
211
- packageManager: opts.pm
372
+ packageManager,
373
+ initGit,
374
+ installDeps
212
375
  });
213
376
  });
214
377
  }
@@ -1032,6 +1195,71 @@ export type ${pascal}DTO = z.infer<typeof ${camel}Schema>
1032
1195
  }
1033
1196
  __name(generateDto, "generateDto");
1034
1197
 
1198
+ // src/generators/config.ts
1199
+ import { join as join9 } from "path";
1200
+ import { existsSync as existsSync2 } from "fs";
1201
+ import { createInterface as createInterface2 } from "readline";
1202
+ async function confirm2(message) {
1203
+ const rl = createInterface2({
1204
+ input: process.stdin,
1205
+ output: process.stdout
1206
+ });
1207
+ return new Promise((resolve3) => {
1208
+ rl.question(` ${message} (y/N) `, (answer) => {
1209
+ rl.close();
1210
+ resolve3(answer.trim().toLowerCase() === "y");
1211
+ });
1212
+ });
1213
+ }
1214
+ __name(confirm2, "confirm");
1215
+ async function generateConfig(options) {
1216
+ const filePath = join9(options.outDir, "kick.config.ts");
1217
+ const modulesDir = options.modulesDir ?? "src/modules";
1218
+ const defaultRepo = options.defaultRepo ?? "inmemory";
1219
+ if (existsSync2(filePath) && !options.force) {
1220
+ const overwrite = await confirm2("kick.config.ts already exists. Overwrite?");
1221
+ if (!overwrite) {
1222
+ console.log("\n Skipped \u2014 existing kick.config.ts preserved.");
1223
+ return [];
1224
+ }
1225
+ }
1226
+ await writeFileSafe(filePath, `import { defineConfig } from '@forinda/kickjs-cli'
1227
+
1228
+ export default defineConfig({
1229
+ modulesDir: '${modulesDir}',
1230
+ defaultRepo: '${defaultRepo}',
1231
+
1232
+ commands: [
1233
+ {
1234
+ name: 'test',
1235
+ description: 'Run tests with Vitest',
1236
+ steps: 'npx vitest run',
1237
+ },
1238
+ {
1239
+ name: 'format',
1240
+ description: 'Format code with Prettier',
1241
+ steps: 'npx prettier --write src/',
1242
+ },
1243
+ {
1244
+ name: 'format:check',
1245
+ description: 'Check formatting without writing',
1246
+ steps: 'npx prettier --check src/',
1247
+ },
1248
+ {
1249
+ name: 'check',
1250
+ description: 'Run typecheck + format check',
1251
+ steps: ['npx tsc --noEmit', 'npx prettier --check src/'],
1252
+ aliases: ['verify', 'ci'],
1253
+ },
1254
+ ],
1255
+ })
1256
+ `);
1257
+ return [
1258
+ filePath
1259
+ ];
1260
+ }
1261
+ __name(generateConfig, "generateConfig");
1262
+
1035
1263
  // src/commands/generate.ts
1036
1264
  function printGenerated(files) {
1037
1265
  const cwd = process.cwd();
@@ -1098,13 +1326,22 @@ function registerGenerateCommand(program) {
1098
1326
  });
1099
1327
  printGenerated(files);
1100
1328
  });
1329
+ gen.command("config").description("Generate a kick.config.ts at the project root").option("--modules-dir <dir>", "Modules directory path", "src/modules").option("--repo <type>", "Default repository type: inmemory | drizzle", "inmemory").option("-f, --force", "Overwrite existing kick.config.ts without prompting").action(async (opts) => {
1330
+ const files = await generateConfig({
1331
+ outDir: resolve2("."),
1332
+ modulesDir: opts.modulesDir,
1333
+ defaultRepo: opts.repo,
1334
+ force: opts.force
1335
+ });
1336
+ printGenerated(files);
1337
+ });
1101
1338
  }
1102
1339
  __name(registerGenerateCommand, "registerGenerateCommand");
1103
1340
 
1104
1341
  // src/utils/shell.ts
1105
- import { execSync } from "child_process";
1342
+ import { execSync as execSync2 } from "child_process";
1106
1343
  function runShellCommand(command, cwd) {
1107
- execSync(command, {
1344
+ execSync2(command, {
1108
1345
  cwd,
1109
1346
  stdio: "inherit"
1110
1347
  });
@@ -1209,7 +1446,7 @@ __name(registerSingleCommand, "registerSingleCommand");
1209
1446
 
1210
1447
  // src/config.ts
1211
1448
  import { readFile as readFile3, access as access2 } from "fs/promises";
1212
- import { join as join9 } from "path";
1449
+ import { join as join10 } from "path";
1213
1450
  var CONFIG_FILES = [
1214
1451
  "kick.config.ts",
1215
1452
  "kick.config.js",
@@ -1218,7 +1455,7 @@ var CONFIG_FILES = [
1218
1455
  ];
1219
1456
  async function loadKickConfig(cwd) {
1220
1457
  for (const filename of CONFIG_FILES) {
1221
- const filepath = join9(cwd, filename);
1458
+ const filepath = join10(cwd, filename);
1222
1459
  try {
1223
1460
  await access2(filepath);
1224
1461
  } catch {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/commands/init.ts","../src/generators/project.ts","../src/utils/fs.ts","../src/commands/generate.ts","../src/generators/module.ts","../src/utils/naming.ts","../src/generators/adapter.ts","../src/generators/middleware.ts","../src/generators/guard.ts","../src/generators/service.ts","../src/generators/controller.ts","../src/generators/dto.ts","../src/utils/shell.ts","../src/commands/run.ts","../src/commands/info.ts","../src/commands/custom.ts","../src/config.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { registerInitCommand } from './commands/init'\nimport { registerGenerateCommand } from './commands/generate'\nimport { registerRunCommands } from './commands/run'\nimport { registerInfoCommand } from './commands/info'\nimport { registerCustomCommands } from './commands/custom'\nimport { loadKickConfig } from './config'\n\nasync function main() {\n const program = new Command()\n\n program\n .name('kick')\n .description('KickJS — A production-grade, decorator-driven Node.js framework')\n .version('0.1.0')\n\n // Load project-level config for custom commands and generator defaults\n const config = await loadKickConfig(process.cwd())\n\n registerInitCommand(program)\n registerGenerateCommand(program)\n registerRunCommands(program)\n registerInfoCommand(program)\n registerCustomCommands(program, config)\n\n program.showHelpAfterError()\n\n await program.parseAsync(process.argv)\n}\n\nmain().catch((err) => {\n console.error(err instanceof Error ? err.message : err)\n process.exitCode = 1\n})\n","import { resolve } from 'node:path'\nimport type { Command } from 'commander'\nimport { initProject } from '../generators/project'\n\nexport function registerInitCommand(program: Command): void {\n program\n .command('new <name>')\n .alias('init')\n .description('Create a new KickJS project')\n .option('-d, --directory <dir>', 'Target directory (defaults to project name)')\n .option('--pm <manager>', 'Package manager: pnpm | npm | yarn', 'pnpm')\n .action(async (name: string, opts: any) => {\n const directory = resolve(opts.directory || name)\n await initProject({\n name,\n directory,\n packageManager: opts.pm,\n })\n })\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\n\ninterface InitProjectOptions {\n name: string\n directory: string\n packageManager?: 'pnpm' | 'npm' | 'yarn'\n}\n\n/** Scaffold a new KickJS project */\nexport async function initProject(options: InitProjectOptions): Promise<void> {\n const { name, directory, packageManager = 'pnpm' } = options\n const dir = directory\n\n console.log(`\\n Creating KickJS project: ${name}\\n`)\n\n // ── package.json ────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'package.json'),\n JSON.stringify(\n {\n name,\n version: '0.1.0',\n type: 'module',\n scripts: {\n dev: 'kick dev',\n 'dev:debug': 'kick dev:debug',\n build: 'kick build',\n start: 'kick start',\n test: 'vitest run',\n 'test:watch': 'vitest',\n typecheck: 'tsc --noEmit',\n lint: 'eslint src/',\n format: 'prettier --write src/',\n },\n dependencies: {\n '@forinda/kickjs-core': '^0.1.0',\n '@forinda/kickjs-http': '^0.1.0',\n '@forinda/kickjs-config': '^0.1.0',\n '@forinda/kickjs-swagger': '^0.1.0',\n express: '^5.1.0',\n 'reflect-metadata': '^0.2.2',\n zod: '^4.3.6',\n pino: '^10.3.1',\n 'pino-pretty': '^13.1.3',\n },\n devDependencies: {\n '@forinda/kickjs-cli': '^0.1.0',\n '@swc/core': '^1.7.28',\n '@types/express': '^5.0.6',\n '@types/node': '^24.5.2',\n 'unplugin-swc': '^1.5.9',\n vite: '^7.3.1',\n 'vite-node': '^5.3.0',\n vitest: '^3.2.4',\n typescript: '^5.9.2',\n prettier: '^3.8.1',\n },\n },\n null,\n 2,\n ),\n )\n\n // ── vite.config.ts — enables HMR + SWC for decorators ──────────────\n await writeFileSafe(\n join(dir, 'vite.config.ts'),\n `import { defineConfig } from 'vite'\nimport { resolve } from 'path'\nimport swc from 'unplugin-swc'\n\nexport default defineConfig({\n plugins: [swc.vite()],\n resolve: {\n alias: {\n '@': resolve(__dirname, 'src'),\n },\n },\n server: {\n watch: { usePolling: false },\n hmr: true,\n },\n build: {\n target: 'node20',\n ssr: true,\n outDir: 'dist',\n sourcemap: true,\n rollupOptions: {\n input: resolve(__dirname, 'src/index.ts'),\n output: { format: 'esm' },\n },\n },\n})\n`,\n )\n\n // ── tsconfig.json ───────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'tsconfig.json'),\n JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n lib: ['ES2022'],\n types: ['node'],\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n sourceMap: true,\n declaration: true,\n experimentalDecorators: true,\n emitDecoratorMetadata: true,\n outDir: 'dist',\n rootDir: 'src',\n paths: { '@/*': ['./src/*'] },\n },\n include: ['src'],\n },\n null,\n 2,\n ),\n )\n\n // ── .prettierrc ─────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, '.prettierrc'),\n JSON.stringify(\n {\n semi: false,\n singleQuote: true,\n trailingComma: 'all',\n printWidth: 100,\n tabWidth: 2,\n },\n null,\n 2,\n ),\n )\n\n // ── .gitignore ──────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, '.gitignore'),\n `node_modules/\ndist/\n.env\ncoverage/\n.DS_Store\n*.tsbuildinfo\n`,\n )\n\n // ── .env ────────────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, '.env'),\n `PORT=3000\nNODE_ENV=development\n`,\n )\n\n await writeFileSafe(\n join(dir, '.env.example'),\n `PORT=3000\nNODE_ENV=development\n`,\n )\n\n // ── src/index.ts — clean entry point with Swagger baked in ────────\n await writeFileSafe(\n join(dir, 'src/index.ts'),\n `import 'reflect-metadata'\nimport { bootstrap } from '@forinda/kickjs-http'\nimport { SwaggerAdapter } from '@forinda/kickjs-swagger'\nimport { modules } from './modules'\n\nbootstrap({\n modules,\n adapters: [\n new SwaggerAdapter({\n info: { title: '${name}', version: '0.1.0' },\n }),\n ],\n})\n`,\n )\n\n // ── src/modules/index.ts ────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'src/modules/index.ts'),\n `import type { AppModuleClass } from '@forinda/kickjs-core'\n\nexport const modules: AppModuleClass[] = []\n`,\n )\n\n // ── vitest.config.ts ────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'vitest.config.ts'),\n `import { defineConfig } from 'vitest/config'\nimport swc from 'unplugin-swc'\n\nexport default defineConfig({\n plugins: [swc.vite()],\n test: {\n globals: true,\n environment: 'node',\n include: ['src/**/*.test.ts'],\n },\n})\n`,\n )\n\n console.log(' Project scaffolded successfully!')\n console.log()\n console.log(' Next steps:')\n console.log(` cd ${name}`)\n console.log(` ${packageManager} install`)\n console.log(` kick g module user`)\n console.log(` kick dev`)\n console.log()\n console.log(' Commands:')\n console.log(' kick dev Start dev server with Vite HMR')\n console.log(' kick build Production build via Vite')\n console.log(' kick start Run production build')\n console.log(' kick g module X Generate a DDD module')\n console.log()\n}\n","import { writeFile, mkdir, access, readFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\n\n/** Write a file, creating parent directories if needed */\nexport async function writeFileSafe(filePath: string, content: string): Promise<void> {\n await mkdir(dirname(filePath), { recursive: true })\n await writeFile(filePath, content, 'utf-8')\n}\n\n/** Ensure a directory exists */\nexport async function ensureDirectory(dir: string): Promise<void> {\n await mkdir(dir, { recursive: true })\n}\n\n/** Check if a file exists */\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath)\n return true\n } catch {\n return false\n }\n}\n\n/** Read a JSON file */\nexport async function readJsonFile<T = any>(filePath: string): Promise<T> {\n const content = await readFile(filePath, 'utf-8')\n return JSON.parse(content)\n}\n","import { resolve } from 'node:path'\nimport type { Command } from 'commander'\nimport { generateModule } from '../generators/module'\nimport { generateAdapter } from '../generators/adapter'\nimport { generateMiddleware } from '../generators/middleware'\nimport { generateGuard } from '../generators/guard'\nimport { generateService } from '../generators/service'\nimport { generateController } from '../generators/controller'\nimport { generateDto } from '../generators/dto'\n\nfunction printGenerated(files: string[]): void {\n const cwd = process.cwd()\n console.log(`\\n Generated ${files.length} file${files.length === 1 ? '' : 's'}:`)\n for (const f of files) {\n console.log(` ${f.replace(cwd + '/', '')}`)\n }\n console.log()\n}\n\nexport function registerGenerateCommand(program: Command): void {\n const gen = program.command('generate').alias('g').description('Generate code scaffolds')\n\n // ── kick g module <name> ────────────────────────────────────────────\n gen\n .command('module <name>')\n .description('Generate a full DDD module with all layers')\n .option('--no-entity', 'Skip entity and value object generation')\n .option('--no-tests', 'Skip test file generation')\n .option('--repo <type>', 'Repository implementation: inmemory | drizzle', 'inmemory')\n .option('--minimal', 'Only generate index.ts and controller')\n .option('--modules-dir <dir>', 'Modules directory', 'src/modules')\n .action(async (name: string, opts: any) => {\n const files = await generateModule({\n name,\n modulesDir: resolve(opts.modulesDir),\n noEntity: opts.entity === false,\n noTests: opts.tests === false,\n repo: opts.repo,\n minimal: opts.minimal,\n })\n printGenerated(files)\n })\n\n // ── kick g adapter <name> ──────────────────────────────────────────\n gen\n .command('adapter <name>')\n .description('Generate an AppAdapter with lifecycle hooks and middleware support')\n .option('-o, --out <dir>', 'Output directory', 'src/adapters')\n .action(async (name: string, opts: any) => {\n const files = await generateAdapter({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n\n // ── kick g middleware <name> ────────────────────────────────────────\n gen\n .command('middleware <name>')\n .description('Generate an Express middleware function')\n .option('-o, --out <dir>', 'Output directory', 'src/middleware')\n .action(async (name: string, opts: any) => {\n const files = await generateMiddleware({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n\n // ── kick g guard <name> ────────────────────────────────────────────\n gen\n .command('guard <name>')\n .description('Generate a route guard (auth, roles, etc.)')\n .option('-o, --out <dir>', 'Output directory', 'src/guards')\n .action(async (name: string, opts: any) => {\n const files = await generateGuard({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n\n // ── kick g service <name> ──────────────────────────────────────────\n gen\n .command('service <name>')\n .description('Generate a @Service() class')\n .option('-o, --out <dir>', 'Output directory', 'src/services')\n .action(async (name: string, opts: any) => {\n const files = await generateService({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n\n // ── kick g controller <name> ───────────────────────────────────────\n gen\n .command('controller <name>')\n .description('Generate a @Controller() class with basic routes')\n .option('-o, --out <dir>', 'Output directory', 'src/controllers')\n .action(async (name: string, opts: any) => {\n const files = await generateController({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n\n // ── kick g dto <name> ──────────────────────────────────────────────\n gen\n .command('dto <name>')\n .description('Generate a Zod DTO schema')\n .option('-o, --out <dir>', 'Output directory', 'src/dtos')\n .action(async (name: string, opts: any) => {\n const files = await generateDto({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n}\n","import { join } from 'node:path'\nimport { writeFileSafe, fileExists } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase, pluralize, pluralizePascal } from '../utils/naming'\nimport { readFile, writeFile } from 'node:fs/promises'\n\ninterface GenerateModuleOptions {\n name: string\n modulesDir: string\n noEntity?: boolean\n noTests?: boolean\n repo?: 'drizzle' | 'inmemory'\n minimal?: boolean\n}\n\n/**\n * Generate a full DDD module with all layers:\n * presentation/ — controller\n * application/ — use-cases, DTOs\n * domain/ — entity, value objects, repository interface, domain service\n * infrastructure/ — repository implementation\n */\nexport async function generateModule(options: GenerateModuleOptions): Promise<string[]> {\n const { name, modulesDir, noEntity, noTests, repo = 'inmemory', minimal } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const camel = toCamelCase(name)\n const plural = pluralize(kebab)\n const pluralPascal = pluralizePascal(pascal)\n const moduleDir = join(modulesDir, plural)\n\n const files: string[] = []\n\n const write = async (relativePath: string, content: string) => {\n const fullPath = join(moduleDir, relativePath)\n await writeFileSafe(fullPath, content)\n files.push(fullPath)\n }\n\n // ── Module Index ────────────────────────────────────────────────────\n await write(\n 'index.ts',\n `/**\n * ${pascal} Module\n *\n * Self-contained feature module following Domain-Driven Design (DDD).\n * Registers dependencies in the DI container and declares HTTP routes.\n *\n * Structure:\n * presentation/ — HTTP controllers (entry points)\n * application/ — Use cases (orchestration) and DTOs (validation)\n * domain/ — Entities, value objects, repository interfaces, domain services\n * infrastructure/ — Repository implementations (in-memory, Drizzle, Prisma, etc.)\n */\nimport { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs-core'\nimport { buildRoutes } from '@forinda/kickjs-http'\nimport { ${pascal.toUpperCase()}_REPOSITORY } from './domain/repositories/${kebab}.repository'\nimport { ${repo === 'inmemory' ? `InMemory${pascal}Repository` : `Drizzle${pascal}Repository`} } from './infrastructure/repositories/${repo === 'inmemory' ? `in-memory-${kebab}` : `drizzle-${kebab}`}.repository'\nimport { ${pascal}Controller } from './presentation/${kebab}.controller'\n\n// Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container\nimport.meta.glob(\n ['./domain/services/**/*.ts', './application/use-cases/**/*.ts', '!./**/*.test.ts'],\n { eager: true },\n)\n\nexport class ${pascal}Module implements AppModule {\n /**\n * Register module dependencies in the DI container.\n * Bind repository interface tokens to their implementations here.\n * To swap implementations (e.g. in-memory -> Drizzle), change the factory target.\n */\n register(container: Container): void {\n container.registerFactory(${pascal.toUpperCase()}_REPOSITORY, () =>\n container.resolve(${repo === 'inmemory' ? `InMemory${pascal}Repository` : `Drizzle${pascal}Repository`}),\n )\n }\n\n /**\n * Declare HTTP routes for this module.\n * The path is prefixed with the global apiPrefix and version (e.g. /api/v1/${plural}).\n * Passing 'controller' enables automatic OpenAPI spec generation via SwaggerAdapter.\n */\n routes(): ModuleRoutes {\n return {\n path: '/${plural}',\n router: buildRoutes(${pascal}Controller),\n controller: ${pascal}Controller,\n }\n }\n}\n`,\n )\n\n // ── Controller ──────────────────────────────────────────────────────\n await write(\n `presentation/${kebab}.controller.ts`,\n `/**\n * ${pascal} Controller\n *\n * Presentation layer — handles HTTP requests and delegates to use cases.\n * Each method receives a RequestContext with typed body, params, and query.\n *\n * Decorators:\n * @Controller(path?) — registers this class as an HTTP controller\n * @Get/@Post/@Put/@Delete(path?, validation?) — defines routes with optional Zod validation\n * @Autowired() — injects dependencies lazily from the DI container\n * @Middleware(...handlers) — attach middleware at class or method level\n *\n * Add Swagger decorators (@ApiTags, @ApiOperation, @ApiResponse) from @forinda/kickjs-swagger\n * for automatic OpenAPI documentation.\n */\nimport { Controller, Get, Post, Put, Delete, Autowired } from '@forinda/kickjs-core'\nimport { RequestContext } from '@forinda/kickjs-http'\nimport { Create${pascal}UseCase } from '../application/use-cases/create-${kebab}.use-case'\nimport { Get${pascal}UseCase } from '../application/use-cases/get-${kebab}.use-case'\nimport { List${pluralPascal}UseCase } from '../application/use-cases/list-${plural}.use-case'\nimport { Update${pascal}UseCase } from '../application/use-cases/update-${kebab}.use-case'\nimport { Delete${pascal}UseCase } from '../application/use-cases/delete-${kebab}.use-case'\nimport { create${pascal}Schema } from '../application/dtos/create-${kebab}.dto'\nimport { update${pascal}Schema } from '../application/dtos/update-${kebab}.dto'\n\n@Controller()\nexport class ${pascal}Controller {\n @Autowired() private create${pascal}UseCase!: Create${pascal}UseCase\n @Autowired() private get${pascal}UseCase!: Get${pascal}UseCase\n @Autowired() private list${pluralPascal}UseCase!: List${pluralPascal}UseCase\n @Autowired() private update${pascal}UseCase!: Update${pascal}UseCase\n @Autowired() private delete${pascal}UseCase!: Delete${pascal}UseCase\n\n @Post('/', { body: create${pascal}Schema })\n async create(ctx: RequestContext) {\n const result = await this.create${pascal}UseCase.execute(ctx.body)\n ctx.created(result)\n }\n\n @Get('/')\n async list(ctx: RequestContext) {\n const result = await this.list${pluralPascal}UseCase.execute()\n ctx.json(result)\n }\n\n @Get('/:id')\n async getById(ctx: RequestContext) {\n const result = await this.get${pascal}UseCase.execute(ctx.params.id)\n if (!result) return ctx.notFound('${pascal} not found')\n ctx.json(result)\n }\n\n @Put('/:id', { body: update${pascal}Schema })\n async update(ctx: RequestContext) {\n const result = await this.update${pascal}UseCase.execute(ctx.params.id, ctx.body)\n ctx.json(result)\n }\n\n @Delete('/:id')\n async remove(ctx: RequestContext) {\n await this.delete${pascal}UseCase.execute(ctx.params.id)\n ctx.noContent()\n }\n}\n`,\n )\n\n // ── DTOs ────────────────────────────────────────────────────────────\n await write(\n `application/dtos/create-${kebab}.dto.ts`,\n `import { z } from 'zod'\n\n/**\n * Create ${pascal} DTO — Zod schema for validating POST request bodies.\n * This schema is passed to @Post('/', { body: create${pascal}Schema }) for automatic validation.\n * It also generates OpenAPI request body docs when SwaggerAdapter is used.\n *\n * Add more fields as needed. Supported Zod types:\n * z.string(), z.number(), z.boolean(), z.enum([...]),\n * z.array(), z.object(), .optional(), .default(), .transform()\n */\nexport const create${pascal}Schema = z.object({\n name: z.string().min(1, 'Name is required').max(200),\n})\n\nexport type Create${pascal}DTO = z.infer<typeof create${pascal}Schema>\n`,\n )\n\n await write(\n `application/dtos/update-${kebab}.dto.ts`,\n `import { z } from 'zod'\n\nexport const update${pascal}Schema = z.object({\n name: z.string().min(1).max(200).optional(),\n})\n\nexport type Update${pascal}DTO = z.infer<typeof update${pascal}Schema>\n`,\n )\n\n await write(\n `application/dtos/${kebab}-response.dto.ts`,\n `export interface ${pascal}ResponseDTO {\n id: string\n name: string\n createdAt: string\n updatedAt: string\n}\n`,\n )\n\n // ── Use Cases ───────────────────────────────────────────────────────\n const useCases = [\n {\n file: `create-${kebab}.use-case.ts`,\n content: `/**\n * Create ${pascal} Use Case\n *\n * Application layer — orchestrates a single business operation.\n * Use cases are thin: validate input (via DTO), call domain/repo, return response.\n * Keep business rules in the domain service, not here.\n */\nimport { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { Create${pascal}DTO } from '../dtos/create-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Create${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.create(dto)\n }\n}\n`,\n },\n {\n file: `get-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Get${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.repo.findById(id)\n }\n}\n`,\n },\n {\n file: `list-${plural}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class List${pluralPascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(): Promise<${pascal}ResponseDTO[]> {\n return this.repo.findAll()\n }\n}\n`,\n },\n {\n file: `update-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { Update${pascal}DTO } from '../dtos/update-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Update${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.update(id, dto)\n }\n}\n`,\n },\n {\n file: `delete-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\n\n@Service()\nexport class Delete${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string): Promise<void> {\n await this.repo.delete(id)\n }\n}\n`,\n },\n ]\n\n for (const uc of useCases) {\n await write(`application/use-cases/${uc.file}`, uc.content)\n }\n\n // ── Domain: Repository Interface ────────────────────────────────────\n await write(\n `domain/repositories/${kebab}.repository.ts`,\n `/**\n * ${pascal} Repository Interface\n *\n * Domain layer — defines the contract for data access.\n * The interface lives in the domain layer; implementations live in infrastructure.\n * This inversion of dependencies keeps the domain pure and testable.\n *\n * To swap implementations (e.g. in-memory -> Drizzle -> Prisma),\n * change the factory in the module's register() method.\n */\nimport type { ${pascal}ResponseDTO } from '../../application/dtos/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '../../application/dtos/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '../../application/dtos/update-${kebab}.dto'\n\nexport interface I${pascal}Repository {\n findById(id: string): Promise<${pascal}ResponseDTO | null>\n findAll(): Promise<${pascal}ResponseDTO[]>\n create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO>\n update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO>\n delete(id: string): Promise<void>\n}\n\nexport const ${pascal.toUpperCase()}_REPOSITORY = Symbol('I${pascal}Repository')\n`,\n )\n\n // ── Domain: Service ─────────────────────────────────────────────────\n await write(\n `domain/services/${kebab}-domain.service.ts`,\n `/**\n * ${pascal} Domain Service\n *\n * Domain layer — contains business rules that don't belong to a single entity.\n * Use this for cross-entity logic, validation rules, and domain invariants.\n * Keep it free of HTTP/framework concerns.\n */\nimport { Service, Inject, HttpException } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../repositories/${kebab}.repository'\n\n@Service()\nexport class ${pascal}DomainService {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async ensureExists(id: string): Promise<void> {\n const entity = await this.repo.findById(id)\n if (!entity) {\n throw HttpException.notFound('${pascal} not found')\n }\n }\n}\n`,\n )\n\n // ── Infrastructure: Repository Implementation ──────────────────────\n if (repo === 'inmemory') {\n await write(\n `infrastructure/repositories/in-memory-${kebab}.repository.ts`,\n `/**\n * In-Memory ${pascal} Repository\n *\n * Infrastructure layer — implements the repository interface using a Map.\n * Useful for prototyping and testing. Replace with a database implementation\n * (Drizzle, Prisma, etc.) for production use.\n *\n * @Repository() registers this class in the DI container as a singleton.\n */\nimport { randomUUID } from 'node:crypto'\nimport { Repository, HttpException } from '@forinda/kickjs-core'\nimport type { I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../../application/dtos/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '../../application/dtos/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '../../application/dtos/update-${kebab}.dto'\n\n@Repository()\nexport class InMemory${pascal}Repository implements I${pascal}Repository {\n private store = new Map<string, ${pascal}ResponseDTO>()\n\n async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.store.get(id) ?? null\n }\n\n async findAll(): Promise<${pascal}ResponseDTO[]> {\n return Array.from(this.store.values())\n }\n\n async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const now = new Date().toISOString()\n const entity: ${pascal}ResponseDTO = {\n id: randomUUID(),\n name: dto.name,\n createdAt: now,\n updatedAt: now,\n }\n this.store.set(entity.id, entity)\n return entity\n }\n\n async update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const existing = this.store.get(id)\n if (!existing) throw HttpException.notFound('${pascal} not found')\n const updated = { ...existing, ...dto, updatedAt: new Date().toISOString() }\n this.store.set(id, updated)\n return updated\n }\n\n async delete(id: string): Promise<void> {\n if (!this.store.has(id)) throw HttpException.notFound('${pascal} not found')\n this.store.delete(id)\n }\n}\n`,\n )\n }\n\n // ── Entity & Value Objects ──────────────────────────────────────────\n if (!noEntity && !minimal) {\n await write(\n `domain/entities/${kebab}.entity.ts`,\n `/**\n * ${pascal} Entity\n *\n * Domain layer — the core business object.\n * Uses a private constructor with static factory methods (create, reconstitute)\n * to enforce invariants. Properties are accessed via getters to maintain encapsulation.\n *\n * Patterns used:\n * - Private constructor: prevents direct instantiation\n * - create(): factory for new entities (generates ID, sets timestamps)\n * - reconstitute(): factory for rebuilding from persistence (no side effects)\n * - changeName(): mutation method that enforces business rules\n */\nimport { ${pascal}Id } from '../value-objects/${kebab}-id.vo'\n\ninterface ${pascal}Props {\n id: ${pascal}Id\n name: string\n createdAt: Date\n updatedAt: Date\n}\n\nexport class ${pascal} {\n private constructor(private props: ${pascal}Props) {}\n\n static create(params: { name: string }): ${pascal} {\n const now = new Date()\n return new ${pascal}({\n id: ${pascal}Id.create(),\n name: params.name,\n createdAt: now,\n updatedAt: now,\n })\n }\n\n static reconstitute(props: ${pascal}Props): ${pascal} {\n return new ${pascal}(props)\n }\n\n get id(): ${pascal}Id {\n return this.props.id\n }\n get name(): string {\n return this.props.name\n }\n get createdAt(): Date {\n return this.props.createdAt\n }\n get updatedAt(): Date {\n return this.props.updatedAt\n }\n\n changeName(name: string): void {\n if (!name || name.trim().length === 0) {\n throw new Error('Name cannot be empty')\n }\n this.props.name = name.trim()\n this.props.updatedAt = new Date()\n }\n\n toJSON() {\n return {\n id: this.props.id.toString(),\n name: this.props.name,\n createdAt: this.props.createdAt.toISOString(),\n updatedAt: this.props.updatedAt.toISOString(),\n }\n }\n}\n`,\n )\n\n await write(\n `domain/value-objects/${kebab}-id.vo.ts`,\n `/**\n * ${pascal} ID Value Object\n *\n * Domain layer — wraps a primitive ID with type safety and validation.\n * Value objects are immutable and compared by value, not reference.\n *\n * ${pascal}Id.create() — generate a new UUID\n * ${pascal}Id.from(id) — wrap an existing ID string (validates non-empty)\n * id.equals(other) — compare two IDs by value\n */\nimport { randomUUID } from 'node:crypto'\n\nexport class ${pascal}Id {\n private constructor(private readonly value: string) {}\n\n static create(): ${pascal}Id {\n return new ${pascal}Id(randomUUID())\n }\n\n static from(id: string): ${pascal}Id {\n if (!id || id.trim().length === 0) {\n throw new Error('${pascal}Id cannot be empty')\n }\n return new ${pascal}Id(id)\n }\n\n toString(): string {\n return this.value\n }\n\n equals(other: ${pascal}Id): boolean {\n return this.value === other.value\n }\n}\n`,\n )\n }\n\n // ── Auto-register in modules index ──────────────────────────────────\n await autoRegisterModule(modulesDir, pascal, plural)\n\n return files\n}\n\n/** Add the new module to src/modules/index.ts */\nasync function autoRegisterModule(\n modulesDir: string,\n pascal: string,\n plural: string,\n): Promise<void> {\n const indexPath = join(modulesDir, 'index.ts')\n const exists = await fileExists(indexPath)\n\n if (!exists) {\n await writeFileSafe(\n indexPath,\n `import type { AppModuleClass } from '@forinda/kickjs-core'\nimport { ${pascal}Module } from './${plural}'\n\nexport const modules: AppModuleClass[] = [${pascal}Module]\n`,\n )\n return\n }\n\n let content = await readFile(indexPath, 'utf-8')\n\n // Add import if not present\n const importLine = `import { ${pascal}Module } from './${plural}'`\n if (!content.includes(`${pascal}Module`)) {\n // Insert import after last existing import\n const lastImportIdx = content.lastIndexOf('import ')\n if (lastImportIdx !== -1) {\n const lineEnd = content.indexOf('\\n', lastImportIdx)\n content = content.slice(0, lineEnd + 1) + importLine + '\\n' + content.slice(lineEnd + 1)\n } else {\n content = importLine + '\\n' + content\n }\n\n // Add to modules array — handle both empty and existing entries\n // Match the array assignment: `= [...]` or `= [\\n...\\n]`\n content = content.replace(/(=\\s*\\[)([\\s\\S]*?)(])/, (_match, open, existing, close) => {\n const trimmed = existing.trim()\n if (!trimmed) {\n // Empty array: `= []`\n return `${open}${pascal}Module${close}`\n }\n // Existing entries: append with comma\n const needsComma = trimmed.endsWith(',') ? '' : ','\n return `${open}${existing.trimEnd()}${needsComma} ${pascal}Module${close}`\n })\n }\n\n await writeFile(indexPath, content, 'utf-8')\n}\n","/** Convert a name to PascalCase */\nexport function toPascalCase(name: string): string {\n return name\n .replace(/[-_\\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))\n .replace(/^(.)/, (c) => c.toUpperCase())\n}\n\n/** Convert a name to camelCase */\nexport function toCamelCase(name: string): string {\n const pascal = toPascalCase(name)\n return pascal.charAt(0).toLowerCase() + pascal.slice(1)\n}\n\n/** Convert a name to kebab-case */\nexport function toKebabCase(name: string): string {\n return name\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\n\n/**\n * Pluralize a kebab-case name for directory/file names.\n * If already plural (ends in 's'), returns as-is.\n */\nexport function pluralize(name: string): string {\n if (name.endsWith('s')) return name\n if (name.endsWith('x') || name.endsWith('z')) return name + 'es'\n if (name.endsWith('sh') || name.endsWith('ch')) return name + 'es'\n if (name.endsWith('y') && !/[aeiou]y$/.test(name)) return name.slice(0, -1) + 'ies'\n return name + 's'\n}\n\n/**\n * Pluralize a PascalCase name for class identifiers.\n * If already plural (ends in 's'), returns as-is.\n * Used for `List${pluralPascal}UseCase` to avoid `ListUserssUseCase`.\n */\nexport function pluralizePascal(name: string): string {\n if (name.endsWith('s')) return name\n if (name.endsWith('x') || name.endsWith('z')) return name + 'es'\n if (name.endsWith('sh') || name.endsWith('ch')) return name + 'es'\n if (name.endsWith('y') && !/[aeiou]y$/i.test(name)) return name.slice(0, -1) + 'ies'\n return name + 's'\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateAdapterOptions {\n name: string\n outDir: string\n}\n\nexport async function generateAdapter(options: GenerateAdapterOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.adapter.ts`)\n await writeFileSafe(\n filePath,\n `import type { Express } from 'express'\nimport type { AppAdapter, AdapterMiddleware, Container } from '@forinda/kickjs-core'\n\nexport interface ${pascal}AdapterOptions {\n // Add your adapter configuration here\n}\n\n/**\n * ${pascal} adapter.\n *\n * Hooks into the Application lifecycle to add middleware, routes,\n * or external service connections.\n *\n * Usage:\n * bootstrap({\n * adapters: [new ${pascal}Adapter({ ... })],\n * })\n */\nexport class ${pascal}Adapter implements AppAdapter {\n name = '${pascal}Adapter'\n\n constructor(private options: ${pascal}AdapterOptions = {}) {}\n\n /**\n * Return middleware entries that the Application will mount.\n * Use \\`phase\\` to control where in the pipeline they run:\n * 'beforeGlobal' | 'afterGlobal' | 'beforeRoutes' | 'afterRoutes'\n */\n middleware(): AdapterMiddleware[] {\n return [\n // Example: add a custom header to all responses\n // {\n // phase: 'beforeGlobal',\n // handler: (_req: any, res: any, next: any) => {\n // res.setHeader('X-${pascal}', 'true')\n // next()\n // },\n // },\n // Example: scope middleware to a specific path\n // {\n // phase: 'beforeRoutes',\n // path: '/api/v1/admin',\n // handler: myAdminMiddleware(),\n // },\n ]\n }\n\n /**\n * Called before global middleware.\n * Use this to mount routes that bypass the middleware stack\n * (health checks, docs UI, static assets).\n */\n beforeMount(app: Express, container: Container): void {\n // Example: mount a status route\n // app.get('/${kebab}/status', (_req, res) => {\n // res.json({ status: 'ok' })\n // })\n }\n\n /**\n * Called after modules and routes are registered, before the server starts.\n * Use this for late-stage DI registrations or config validation.\n */\n beforeStart(app: Express, container: Container): void {\n // Example: register a service in the DI container\n // container.registerInstance(MY_TOKEN, new MyService(this.options))\n }\n\n /**\n * Called after the HTTP server is listening.\n * Use this to attach to the raw http.Server (Socket.IO, gRPC, etc).\n */\n afterStart(server: any, container: Container): void {\n // Example: attach Socket.IO\n // const io = new Server(server)\n // container.registerInstance(SOCKET_IO, io)\n }\n\n /**\n * Called on graceful shutdown. Clean up connections.\n */\n async shutdown(): Promise<void> {\n // Example: close a connection pool\n // await this.pool.end()\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\n\ninterface GenerateMiddlewareOptions {\n name: string\n outDir: string\n}\n\nexport async function generateMiddleware(options: GenerateMiddlewareOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const camel = toCamelCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.middleware.ts`)\n await writeFileSafe(\n filePath,\n `import type { Request, Response, NextFunction } from 'express'\n\nexport interface ${toPascalCase(name)}Options {\n // Add configuration options here\n}\n\n/**\n * ${toPascalCase(name)} middleware.\n *\n * Usage in bootstrap:\n * middleware: [${camel}()]\n *\n * Usage with adapter:\n * middleware() { return [{ handler: ${camel}(), phase: 'afterGlobal' }] }\n *\n * Usage with @Middleware decorator:\n * @Middleware(${camel}())\n */\nexport function ${camel}(options: ${toPascalCase(name)}Options = {}) {\n return (req: Request, res: Response, next: NextFunction) => {\n // Implement your middleware logic here\n next()\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\n\ninterface GenerateGuardOptions {\n name: string\n outDir: string\n}\n\nexport async function generateGuard(options: GenerateGuardOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const camel = toCamelCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.guard.ts`)\n await writeFileSafe(\n filePath,\n `import { Container, HttpException } from '@forinda/kickjs-core'\nimport type { RequestContext } from '@forinda/kickjs-http'\n\n/**\n * ${pascal} guard.\n *\n * Guards protect routes by checking conditions before the handler runs.\n * Return early with an error response to block access.\n *\n * Usage:\n * @Middleware(${camel}Guard)\n * @Get('/protected')\n * async handler(ctx: RequestContext) { ... }\n */\nexport async function ${camel}Guard(ctx: RequestContext, next: () => void): Promise<void> {\n // Example: check for an authorization header\n const header = ctx.headers.authorization\n if (!header?.startsWith('Bearer ')) {\n ctx.res.status(401).json({ message: 'Missing or invalid authorization header' })\n return\n }\n\n const token = header.slice(7)\n\n try {\n // Verify the token using a service from the DI container\n // const container = Container.getInstance()\n // const authService = container.resolve(AuthService)\n // const payload = authService.verifyToken(token)\n // ctx.set('auth', payload)\n\n next()\n } catch {\n ctx.res.status(401).json({ message: 'Invalid or expired token' })\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateServiceOptions {\n name: string\n outDir: string\n}\n\nexport async function generateService(options: GenerateServiceOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.service.ts`)\n await writeFileSafe(\n filePath,\n `import { Service } from '@forinda/kickjs-core'\n\n@Service()\nexport class ${pascal}Service {\n // Inject dependencies via constructor\n // constructor(\n // @Inject(MY_REPO) private readonly repo: IMyRepository,\n // ) {}\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateControllerOptions {\n name: string\n outDir: string\n}\n\nexport async function generateController(options: GenerateControllerOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.controller.ts`)\n await writeFileSafe(\n filePath,\n `import { Controller, Get, Post, Autowired } from '@forinda/kickjs-core'\nimport type { RequestContext } from '@forinda/kickjs-http'\n\n@Controller()\nexport class ${pascal}Controller {\n // @Autowired() private myService!: MyService\n\n @Get('/')\n async list(ctx: RequestContext) {\n ctx.json({ message: '${pascal} list' })\n }\n\n @Post('/')\n async create(ctx: RequestContext) {\n ctx.created({ message: '${pascal} created', data: ctx.body })\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\n\ninterface GenerateDtoOptions {\n name: string\n outDir: string\n}\n\nexport async function generateDto(options: GenerateDtoOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const camel = toCamelCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.dto.ts`)\n await writeFileSafe(\n filePath,\n `import { z } from 'zod'\n\nexport const ${camel}Schema = z.object({\n // Define your schema fields here\n name: z.string().min(1).max(200),\n})\n\nexport type ${pascal}DTO = z.infer<typeof ${camel}Schema>\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { execSync } from 'node:child_process'\n\n/** Run a shell command synchronously, printing output */\nexport function runShellCommand(command: string, cwd?: string): void {\n execSync(command, {\n cwd,\n stdio: 'inherit',\n })\n}\n","import type { Command } from 'commander'\nimport { runShellCommand } from '../utils/shell'\n\nexport function registerRunCommands(program: Command): void {\n program\n .command('dev')\n .description('Start development server with Vite HMR (zero-downtime reload)')\n .option('-e, --entry <file>', 'Entry file', 'src/index.ts')\n .option('-p, --port <port>', 'Port number')\n .action((opts: any) => {\n const envVars: string[] = []\n if (opts.port) envVars.push(`PORT=${opts.port}`)\n\n // vite-node --watch gives true HMR via import.meta.hot.accept()\n // The Application.rebuild() swaps the Express handler on the existing\n // http.Server — DB, Redis, Socket.IO connections survive across reloads\n const cmd = `npx vite-node --watch ${opts.entry}`\n const fullCmd = envVars.length ? `${envVars.join(' ')} ${cmd}` : cmd\n\n console.log(`\\n KickJS dev server starting...`)\n console.log(` Entry: ${opts.entry}`)\n console.log(` HMR: enabled (vite-node)\\n`)\n\n try {\n runShellCommand(fullCmd)\n } catch {\n // Process exits on SIGINT — expected\n }\n })\n\n program\n .command('build')\n .description('Build for production via Vite')\n .action(() => {\n console.log('\\n Building for production...\\n')\n runShellCommand('npx vite build')\n })\n\n program\n .command('start')\n .description('Start production server')\n .option('-e, --entry <file>', 'Entry file', 'dist/index.js')\n .option('-p, --port <port>', 'Port number')\n .action((opts: any) => {\n const envVars: string[] = ['NODE_ENV=production']\n if (opts.port) envVars.push(`PORT=${opts.port}`)\n runShellCommand(`${envVars.join(' ')} node ${opts.entry}`)\n })\n\n program\n .command('dev:debug')\n .description('Start dev server with Node.js inspector')\n .option('-e, --entry <file>', 'Entry file', 'src/index.ts')\n .option('-p, --port <port>', 'Port number')\n .action((opts: any) => {\n const envVars = opts.port ? `PORT=${opts.port} ` : ''\n try {\n runShellCommand(`${envVars}npx vite-node --inspect --watch ${opts.entry}`)\n } catch {\n // SIGINT\n }\n })\n}\n","import { platform, release, arch } from 'node:os'\nimport type { Command } from 'commander'\n\nexport function registerInfoCommand(program: Command): void {\n program\n .command('info')\n .description('Print system and framework info')\n .action(() => {\n console.log(`\n KickJS CLI\n\n System:\n OS: ${platform()} ${release()} (${arch()})\n Node: ${process.version}\n\n Packages:\n @forinda/kickjs-core workspace\n @forinda/kickjs-http workspace\n @forinda/kickjs-config workspace\n @forinda/kickjs-cli workspace\n`)\n })\n}\n","import type { Command } from 'commander'\nimport type { KickConfig, KickCommandDefinition } from '../config'\nimport { runShellCommand } from '../utils/shell'\n\n/**\n * Register custom commands defined in kick.config.ts\n *\n * Developers can extend the CLI with project-specific commands like:\n * kick db:migrate\n * kick db:generate\n * kick seed\n * kick proto:gen\n *\n * @example kick.config.ts\n * ```ts\n * import { defineConfig } from '@forinda/kickjs-cli'\n *\n * export default defineConfig({\n * commands: [\n * {\n * name: 'db:generate',\n * description: 'Generate Drizzle migrations from schema',\n * steps: 'npx drizzle-kit generate',\n * },\n * {\n * name: 'db:migrate',\n * description: 'Run database migrations',\n * steps: 'npx drizzle-kit migrate',\n * },\n * {\n * name: 'db:push',\n * description: 'Push schema directly (dev only)',\n * steps: 'npx drizzle-kit push',\n * },\n * {\n * name: 'db:studio',\n * description: 'Open Drizzle Studio GUI',\n * steps: 'npx drizzle-kit studio',\n * },\n * {\n * name: 'db:seed',\n * description: 'Run seed files',\n * steps: 'npx tsx src/db/seed.ts',\n * },\n * {\n * name: 'proto:gen',\n * description: 'Generate TypeScript from protobuf definitions',\n * steps: [\n * 'npx buf generate',\n * 'echo \"Protobuf types generated\"',\n * ],\n * },\n * ],\n * })\n * ```\n */\nexport function registerCustomCommands(program: Command, config: KickConfig | null): void {\n if (!config?.commands?.length) return\n\n for (const cmd of config.commands) {\n registerSingleCommand(program, cmd)\n }\n}\n\nfunction registerSingleCommand(program: Command, def: KickCommandDefinition): void {\n const command = program.command(def.name).description(def.description)\n\n if (def.aliases) {\n for (const alias of def.aliases) {\n command.alias(alias)\n }\n }\n\n // Accept arbitrary trailing arguments\n command.allowUnknownOption(true)\n command.argument('[args...]', 'Additional arguments passed to the command')\n\n command.action((args: string[]) => {\n const extraArgs = args.join(' ')\n const steps = Array.isArray(def.steps) ? def.steps : [def.steps]\n\n for (const step of steps) {\n // Replace {args} placeholder with CLI arguments\n const finalCmd = extraArgs ? `${step} ${extraArgs}` : step\n console.log(` $ ${finalCmd}`)\n try {\n runShellCommand(finalCmd)\n } catch (err: any) {\n console.error(` Command failed: ${def.name}`)\n process.exitCode = 1\n return\n }\n }\n })\n}\n","import { readFile, access } from 'node:fs/promises'\nimport { join } from 'node:path'\n\n/** A custom command that developers can register via kick.config.ts */\nexport interface KickCommandDefinition {\n /** The command name (e.g. 'db:migrate', 'seed', 'proto:gen') */\n name: string\n /** Description shown in --help */\n description: string\n /**\n * Shell command(s) to run. Can be a single string or an array of\n * sequential steps. Use {args} as a placeholder for CLI arguments.\n *\n * @example\n * 'npx drizzle-kit migrate'\n * ['npx drizzle-kit generate', 'npx drizzle-kit migrate']\n */\n steps: string | string[]\n /** Optional aliases (e.g. ['migrate'] for 'db:migrate') */\n aliases?: string[]\n}\n\n/** Configuration for the kick.config.ts file */\nexport interface KickConfig {\n /** Where modules live (default: 'src/modules') */\n modulesDir?: string\n /** Default repository implementation for generators */\n defaultRepo?: 'drizzle' | 'inmemory' | 'prisma'\n /** Drizzle schema output directory */\n schemaDir?: string\n /** Custom commands that extend the CLI */\n commands?: KickCommandDefinition[]\n /** Code style overrides (auto-detected from prettier when possible) */\n style?: {\n semicolons?: boolean\n quotes?: 'single' | 'double'\n trailingComma?: 'all' | 'es5' | 'none'\n indent?: number\n }\n}\n\n/** Helper to define a type-safe kick.config.ts */\nexport function defineConfig(config: KickConfig): KickConfig {\n return config\n}\n\nconst CONFIG_FILES = ['kick.config.ts', 'kick.config.js', 'kick.config.mjs', 'kick.config.json']\n\n/** Load kick.config.* from the project root */\nexport async function loadKickConfig(cwd: string): Promise<KickConfig | null> {\n for (const filename of CONFIG_FILES) {\n const filepath = join(cwd, filename)\n try {\n await access(filepath)\n } catch {\n continue\n }\n\n if (filename.endsWith('.json')) {\n const content = await readFile(filepath, 'utf-8')\n return JSON.parse(content)\n }\n\n // For .ts/.js/.mjs — dynamic import (use file URL for cross-platform compat)\n try {\n const { pathToFileURL } = await import('node:url')\n const mod = await import(pathToFileURL(filepath).href)\n return mod.default ?? mod\n } catch (err) {\n if (filename.endsWith('.ts')) {\n console.warn(\n `Warning: Failed to load ${filename}. TypeScript config files require ` +\n 'a runtime loader (e.g. tsx, ts-node) or use kick.config.js/.mjs instead.',\n )\n }\n continue\n }\n }\n return null\n}\n"],"mappings":"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","names":["Command","resolve","join","writeFile","mkdir","access","readFile","dirname","writeFileSafe","filePath","content","mkdir","dirname","recursive","writeFile","fileExists","filePath","access","initProject","options","name","directory","packageManager","dir","console","log","writeFileSafe","join","JSON","stringify","version","type","scripts","dev","build","start","test","typecheck","lint","format","dependencies","express","zod","pino","devDependencies","vite","vitest","typescript","prettier","compilerOptions","target","module","moduleResolution","lib","types","strict","esModuleInterop","skipLibCheck","sourceMap","declaration","experimentalDecorators","emitDecoratorMetadata","outDir","rootDir","paths","include","semi","singleQuote","trailingComma","printWidth","tabWidth","registerInitCommand","program","command","alias","description","option","action","name","opts","directory","resolve","initProject","packageManager","pm","resolve","join","toPascalCase","name","replace","_","c","toUpperCase","toCamelCase","pascal","charAt","toLowerCase","slice","toKebabCase","pluralize","endsWith","test","pluralizePascal","readFile","writeFile","generateModule","options","name","modulesDir","noEntity","noTests","repo","minimal","kebab","toKebabCase","pascal","toPascalCase","camel","toCamelCase","plural","pluralize","pluralPascal","pluralizePascal","moduleDir","join","files","write","relativePath","content","fullPath","writeFileSafe","push","toUpperCase","useCases","file","uc","autoRegisterModule","indexPath","exists","fileExists","readFile","importLine","includes","lastImportIdx","lastIndexOf","lineEnd","indexOf","slice","replace","_match","open","existing","close","trimmed","trim","needsComma","endsWith","trimEnd","writeFile","join","generateAdapter","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateMiddleware","options","name","outDir","kebab","toKebabCase","camel","toCamelCase","files","filePath","join","writeFileSafe","toPascalCase","push","join","generateGuard","options","name","outDir","kebab","toKebabCase","camel","toCamelCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateService","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateController","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateDto","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","camel","toCamelCase","files","filePath","join","writeFileSafe","push","printGenerated","files","cwd","process","console","log","length","f","replace","registerGenerateCommand","program","gen","command","alias","description","option","action","name","opts","generateModule","modulesDir","resolve","noEntity","entity","noTests","tests","repo","minimal","generateAdapter","outDir","out","generateMiddleware","generateGuard","generateService","generateController","generateDto","execSync","runShellCommand","command","cwd","execSync","stdio","registerRunCommands","program","command","description","option","action","opts","envVars","port","push","cmd","entry","fullCmd","length","join","console","log","runShellCommand","platform","release","arch","registerInfoCommand","program","command","description","action","console","log","platform","release","arch","process","version","registerCustomCommands","program","config","commands","length","cmd","registerSingleCommand","def","command","name","description","aliases","alias","allowUnknownOption","argument","action","args","extraArgs","join","steps","Array","isArray","step","finalCmd","console","log","runShellCommand","err","error","process","exitCode","readFile","access","join","CONFIG_FILES","loadKickConfig","cwd","filename","filepath","join","access","endsWith","content","readFile","JSON","parse","pathToFileURL","mod","href","default","err","console","warn","main","program","Command","name","description","version","config","loadKickConfig","process","cwd","registerInitCommand","registerGenerateCommand","registerRunCommands","registerInfoCommand","registerCustomCommands","showHelpAfterError","parseAsync","argv","catch","err","console","error","Error","message","exitCode"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/commands/init.ts","../src/generators/project.ts","../src/utils/fs.ts","../src/commands/generate.ts","../src/generators/module.ts","../src/utils/naming.ts","../src/generators/adapter.ts","../src/generators/middleware.ts","../src/generators/guard.ts","../src/generators/service.ts","../src/generators/controller.ts","../src/generators/dto.ts","../src/generators/config.ts","../src/utils/shell.ts","../src/commands/run.ts","../src/commands/info.ts","../src/commands/custom.ts","../src/config.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { registerInitCommand } from './commands/init'\nimport { registerGenerateCommand } from './commands/generate'\nimport { registerRunCommands } from './commands/run'\nimport { registerInfoCommand } from './commands/info'\nimport { registerCustomCommands } from './commands/custom'\nimport { loadKickConfig } from './config'\n\nasync function main() {\n const program = new Command()\n\n program\n .name('kick')\n .description('KickJS — A production-grade, decorator-driven Node.js framework')\n .version('0.1.0')\n\n // Load project-level config for custom commands and generator defaults\n const config = await loadKickConfig(process.cwd())\n\n registerInitCommand(program)\n registerGenerateCommand(program)\n registerRunCommands(program)\n registerInfoCommand(program)\n registerCustomCommands(program, config)\n\n program.showHelpAfterError()\n\n await program.parseAsync(process.argv)\n}\n\nmain().catch((err) => {\n console.error(err instanceof Error ? err.message : err)\n process.exitCode = 1\n})\n","import { resolve, basename } from 'node:path'\nimport { createInterface } from 'node:readline'\nimport { existsSync, readdirSync, rmSync } from 'node:fs'\nimport type { Command } from 'commander'\nimport { initProject } from '../generators/project'\n\nfunction ask(question: string, defaultValue?: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout })\n const suffix = defaultValue ? ` (${defaultValue})` : ''\n return new Promise((res) => {\n rl.question(` ${question}${suffix}: `, (answer) => {\n rl.close()\n res(answer.trim() || defaultValue || '')\n })\n })\n}\n\nasync function choose(question: string, options: string[], defaultIdx = 0): Promise<string> {\n console.log(` ${question}`)\n for (let i = 0; i < options.length; i++) {\n const marker = i === defaultIdx ? '>' : ' '\n console.log(` ${marker} ${i + 1}. ${options[i]}`)\n }\n const answer = await ask('Choose', String(defaultIdx + 1))\n const idx = parseInt(answer, 10) - 1\n return options[idx] ?? options[defaultIdx]\n}\n\nasync function confirm(question: string, defaultYes = true): Promise<boolean> {\n const hint = defaultYes ? 'Y/n' : 'y/N'\n const answer = await ask(`${question} (${hint})`)\n if (!answer) return defaultYes\n return answer.toLowerCase().startsWith('y')\n}\n\nexport function registerInitCommand(program: Command): void {\n program\n .command('new [name]')\n .alias('init')\n .description('Create a new KickJS project (use \".\" for current directory)')\n .option('-d, --directory <dir>', 'Target directory (defaults to project name)')\n .option('--pm <manager>', 'Package manager: pnpm | npm | yarn')\n .option('--git', 'Initialize git repository')\n .option('--no-git', 'Skip git initialization')\n .option('--install', 'Install dependencies after scaffolding')\n .option('--no-install', 'Skip dependency installation')\n .option('-f, --force', 'Remove existing files without prompting')\n .action(async (name: string | undefined, opts: any) => {\n console.log()\n\n // Resolve project name — support \".\" for current directory\n if (!name) {\n name = await ask('Project name', 'my-api')\n }\n\n let directory: string\n if (name === '.') {\n directory = resolve('.')\n name = basename(directory)\n } else {\n directory = resolve(opts.directory || name)\n }\n\n // Check if target directory exists and is non-empty\n if (existsSync(directory)) {\n const entries = readdirSync(directory)\n if (entries.length > 0) {\n if (opts.force) {\n console.log(` Clearing existing files in ${directory}...\\n`)\n } else {\n console.log(` Directory \"${name}\" is not empty:`)\n const shown = entries.slice(0, 5)\n for (const entry of shown) {\n console.log(` - ${entry}`)\n }\n if (entries.length > 5) {\n console.log(` ... and ${entries.length - 5} more`)\n }\n console.log()\n const shouldClear = await confirm('Remove all existing files and proceed?', false)\n if (!shouldClear) {\n console.log(' Aborted.\\n')\n return\n }\n }\n // Remove contents but keep the directory itself\n for (const entry of entries) {\n rmSync(resolve(directory, entry), { recursive: true, force: true })\n }\n }\n }\n\n // Package manager — prompt if not provided via --pm\n let packageManager = opts.pm\n if (!packageManager) {\n packageManager = await choose('Package manager:', ['pnpm', 'npm', 'yarn'], 0)\n }\n\n // Git init — prompt if not explicitly set\n let initGit: boolean\n if (opts.git === undefined) {\n initGit = await confirm('Initialize git repository?', true)\n } else {\n initGit = opts.git\n }\n\n // Install deps — prompt if not explicitly set\n let installDeps: boolean\n if (opts.install === undefined) {\n installDeps = await confirm('Install dependencies?', true)\n } else {\n installDeps = opts.install\n }\n\n await initProject({\n name,\n directory,\n packageManager,\n initGit,\n installDeps,\n })\n })\n}\n","import { join } from 'node:path'\nimport { execSync } from 'node:child_process'\nimport { writeFileSafe } from '../utils/fs'\n\ninterface InitProjectOptions {\n name: string\n directory: string\n packageManager?: 'pnpm' | 'npm' | 'yarn'\n initGit?: boolean\n installDeps?: boolean\n}\n\n/** Scaffold a new KickJS project */\nexport async function initProject(options: InitProjectOptions): Promise<void> {\n const { name, directory, packageManager = 'pnpm' } = options\n const dir = directory\n\n console.log(`\\n Creating KickJS project: ${name}\\n`)\n\n // ── package.json ────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'package.json'),\n JSON.stringify(\n {\n name,\n version: '0.1.0',\n type: 'module',\n scripts: {\n dev: 'kick dev',\n 'dev:debug': 'kick dev:debug',\n build: 'kick build',\n start: 'kick start',\n test: 'vitest run',\n 'test:watch': 'vitest',\n typecheck: 'tsc --noEmit',\n lint: 'eslint src/',\n format: 'prettier --write src/',\n },\n dependencies: {\n '@forinda/kickjs-core': '^0.1.0',\n '@forinda/kickjs-http': '^0.1.0',\n '@forinda/kickjs-config': '^0.1.0',\n '@forinda/kickjs-swagger': '^0.1.0',\n express: '^5.1.0',\n 'reflect-metadata': '^0.2.2',\n zod: '^4.3.6',\n pino: '^10.3.1',\n 'pino-pretty': '^13.1.3',\n },\n devDependencies: {\n '@forinda/kickjs-cli': '^0.1.0',\n '@swc/core': '^1.7.28',\n '@types/express': '^5.0.6',\n '@types/node': '^24.5.2',\n 'unplugin-swc': '^1.5.9',\n vite: '^7.3.1',\n 'vite-node': '^5.3.0',\n vitest: '^3.2.4',\n typescript: '^5.9.2',\n prettier: '^3.8.1',\n },\n },\n null,\n 2,\n ),\n )\n\n // ── vite.config.ts — enables HMR + SWC for decorators ──────────────\n await writeFileSafe(\n join(dir, 'vite.config.ts'),\n `import { defineConfig } from 'vite'\nimport { resolve } from 'path'\nimport swc from 'unplugin-swc'\n\nexport default defineConfig({\n plugins: [swc.vite()],\n resolve: {\n alias: {\n '@': resolve(__dirname, 'src'),\n },\n },\n server: {\n watch: { usePolling: false },\n hmr: true,\n },\n build: {\n target: 'node20',\n ssr: true,\n outDir: 'dist',\n sourcemap: true,\n rollupOptions: {\n input: resolve(__dirname, 'src/index.ts'),\n output: { format: 'esm' },\n },\n },\n})\n`,\n )\n\n // ── tsconfig.json ───────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'tsconfig.json'),\n JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n lib: ['ES2022'],\n types: ['node'],\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n sourceMap: true,\n declaration: true,\n experimentalDecorators: true,\n emitDecoratorMetadata: true,\n outDir: 'dist',\n rootDir: 'src',\n paths: { '@/*': ['./src/*'] },\n },\n include: ['src'],\n },\n null,\n 2,\n ),\n )\n\n // ── .prettierrc ─────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, '.prettierrc'),\n JSON.stringify(\n {\n semi: false,\n singleQuote: true,\n trailingComma: 'all',\n printWidth: 100,\n tabWidth: 2,\n },\n null,\n 2,\n ),\n )\n\n // ── .gitignore ──────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, '.gitignore'),\n `node_modules/\ndist/\n.env\ncoverage/\n.DS_Store\n*.tsbuildinfo\n`,\n )\n\n // ── .env ────────────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, '.env'),\n `PORT=3000\nNODE_ENV=development\n`,\n )\n\n await writeFileSafe(\n join(dir, '.env.example'),\n `PORT=3000\nNODE_ENV=development\n`,\n )\n\n // ── src/index.ts — clean entry point with Swagger baked in ────────\n await writeFileSafe(\n join(dir, 'src/index.ts'),\n `import 'reflect-metadata'\nimport { bootstrap } from '@forinda/kickjs-http'\nimport { SwaggerAdapter } from '@forinda/kickjs-swagger'\nimport { modules } from './modules'\n\nbootstrap({\n modules,\n adapters: [\n new SwaggerAdapter({\n info: { title: '${name}', version: '0.1.0' },\n }),\n ],\n})\n`,\n )\n\n // ── src/modules/index.ts ────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'src/modules/index.ts'),\n `import type { AppModuleClass } from '@forinda/kickjs-core'\n\nexport const modules: AppModuleClass[] = []\n`,\n )\n\n // ── kick.config.ts — CLI configuration ─────────────────────────────\n await writeFileSafe(\n join(dir, 'kick.config.ts'),\n `import { defineConfig } from '@forinda/kickjs-cli'\n\nexport default defineConfig({\n modulesDir: 'src/modules',\n defaultRepo: 'inmemory',\n\n commands: [\n {\n name: 'test',\n description: 'Run tests with Vitest',\n steps: 'npx vitest run',\n },\n {\n name: 'format',\n description: 'Format code with Prettier',\n steps: 'npx prettier --write src/',\n },\n {\n name: 'format:check',\n description: 'Check formatting without writing',\n steps: 'npx prettier --check src/',\n },\n {\n name: 'check',\n description: 'Run typecheck + format check',\n steps: ['npx tsc --noEmit', 'npx prettier --check src/'],\n aliases: ['verify', 'ci'],\n },\n ],\n})\n`,\n )\n\n // ── vitest.config.ts ────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'vitest.config.ts'),\n `import { defineConfig } from 'vitest/config'\nimport swc from 'unplugin-swc'\n\nexport default defineConfig({\n plugins: [swc.vite()],\n test: {\n globals: true,\n environment: 'node',\n include: ['src/**/*.test.ts'],\n },\n})\n`,\n )\n\n // ── Git Init ─────────────────────────────────────────────────────────\n if (options.initGit) {\n try {\n execSync('git init', { cwd: dir, stdio: 'pipe' })\n execSync('git add -A', { cwd: dir, stdio: 'pipe' })\n execSync('git commit -m \"chore: initial commit from kick new\"', {\n cwd: dir,\n stdio: 'pipe',\n })\n console.log(' Git repository initialized')\n } catch {\n console.log(' Warning: git init failed (git may not be installed)')\n }\n }\n\n // ── Install Dependencies ────────────────────────────────────────────\n if (options.installDeps) {\n console.log(`\\n Installing dependencies with ${packageManager}...\\n`)\n try {\n execSync(`${packageManager} install`, { cwd: dir, stdio: 'inherit' })\n console.log('\\n Dependencies installed successfully!')\n } catch {\n console.log(`\\n Warning: ${packageManager} install failed. Run it manually.`)\n }\n }\n\n console.log('\\n Project scaffolded successfully!')\n console.log()\n\n const needsCd = dir !== process.cwd()\n console.log(' Next steps:')\n if (needsCd) console.log(` cd ${name}`)\n if (!options.installDeps) console.log(` ${packageManager} install`)\n console.log(' kick g module user')\n console.log(' kick dev')\n console.log()\n console.log(' Commands:')\n console.log(' kick dev Start dev server with Vite HMR')\n console.log(' kick build Production build via Vite')\n console.log(' kick start Run production build')\n console.log(' kick g module X Generate a DDD module')\n console.log()\n}\n","import { writeFile, mkdir, access, readFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\n\n/** Write a file, creating parent directories if needed */\nexport async function writeFileSafe(filePath: string, content: string): Promise<void> {\n await mkdir(dirname(filePath), { recursive: true })\n await writeFile(filePath, content, 'utf-8')\n}\n\n/** Ensure a directory exists */\nexport async function ensureDirectory(dir: string): Promise<void> {\n await mkdir(dir, { recursive: true })\n}\n\n/** Check if a file exists */\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath)\n return true\n } catch {\n return false\n }\n}\n\n/** Read a JSON file */\nexport async function readJsonFile<T = any>(filePath: string): Promise<T> {\n const content = await readFile(filePath, 'utf-8')\n return JSON.parse(content)\n}\n","import { resolve } from 'node:path'\nimport type { Command } from 'commander'\nimport { generateModule } from '../generators/module'\nimport { generateAdapter } from '../generators/adapter'\nimport { generateMiddleware } from '../generators/middleware'\nimport { generateGuard } from '../generators/guard'\nimport { generateService } from '../generators/service'\nimport { generateController } from '../generators/controller'\nimport { generateDto } from '../generators/dto'\nimport { generateConfig } from '../generators/config'\n\nfunction printGenerated(files: string[]): void {\n const cwd = process.cwd()\n console.log(`\\n Generated ${files.length} file${files.length === 1 ? '' : 's'}:`)\n for (const f of files) {\n console.log(` ${f.replace(cwd + '/', '')}`)\n }\n console.log()\n}\n\nexport function registerGenerateCommand(program: Command): void {\n const gen = program.command('generate').alias('g').description('Generate code scaffolds')\n\n // ── kick g module <name> ────────────────────────────────────────────\n gen\n .command('module <name>')\n .description('Generate a full DDD module with all layers')\n .option('--no-entity', 'Skip entity and value object generation')\n .option('--no-tests', 'Skip test file generation')\n .option('--repo <type>', 'Repository implementation: inmemory | drizzle', 'inmemory')\n .option('--minimal', 'Only generate index.ts and controller')\n .option('--modules-dir <dir>', 'Modules directory', 'src/modules')\n .action(async (name: string, opts: any) => {\n const files = await generateModule({\n name,\n modulesDir: resolve(opts.modulesDir),\n noEntity: opts.entity === false,\n noTests: opts.tests === false,\n repo: opts.repo,\n minimal: opts.minimal,\n })\n printGenerated(files)\n })\n\n // ── kick g adapter <name> ──────────────────────────────────────────\n gen\n .command('adapter <name>')\n .description('Generate an AppAdapter with lifecycle hooks and middleware support')\n .option('-o, --out <dir>', 'Output directory', 'src/adapters')\n .action(async (name: string, opts: any) => {\n const files = await generateAdapter({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n\n // ── kick g middleware <name> ────────────────────────────────────────\n gen\n .command('middleware <name>')\n .description('Generate an Express middleware function')\n .option('-o, --out <dir>', 'Output directory', 'src/middleware')\n .action(async (name: string, opts: any) => {\n const files = await generateMiddleware({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n\n // ── kick g guard <name> ────────────────────────────────────────────\n gen\n .command('guard <name>')\n .description('Generate a route guard (auth, roles, etc.)')\n .option('-o, --out <dir>', 'Output directory', 'src/guards')\n .action(async (name: string, opts: any) => {\n const files = await generateGuard({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n\n // ── kick g service <name> ──────────────────────────────────────────\n gen\n .command('service <name>')\n .description('Generate a @Service() class')\n .option('-o, --out <dir>', 'Output directory', 'src/services')\n .action(async (name: string, opts: any) => {\n const files = await generateService({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n\n // ── kick g controller <name> ───────────────────────────────────────\n gen\n .command('controller <name>')\n .description('Generate a @Controller() class with basic routes')\n .option('-o, --out <dir>', 'Output directory', 'src/controllers')\n .action(async (name: string, opts: any) => {\n const files = await generateController({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n\n // ── kick g dto <name> ──────────────────────────────────────────────\n gen\n .command('dto <name>')\n .description('Generate a Zod DTO schema')\n .option('-o, --out <dir>', 'Output directory', 'src/dtos')\n .action(async (name: string, opts: any) => {\n const files = await generateDto({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n\n // ── kick g config ────────────────────────────────────────────────────\n gen\n .command('config')\n .description('Generate a kick.config.ts at the project root')\n .option('--modules-dir <dir>', 'Modules directory path', 'src/modules')\n .option('--repo <type>', 'Default repository type: inmemory | drizzle', 'inmemory')\n .option('-f, --force', 'Overwrite existing kick.config.ts without prompting')\n .action(async (opts: any) => {\n const files = await generateConfig({\n outDir: resolve('.'),\n modulesDir: opts.modulesDir,\n defaultRepo: opts.repo,\n force: opts.force,\n })\n printGenerated(files)\n })\n}\n","import { join } from 'node:path'\nimport { writeFileSafe, fileExists } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase, pluralize, pluralizePascal } from '../utils/naming'\nimport { readFile, writeFile } from 'node:fs/promises'\n\ninterface GenerateModuleOptions {\n name: string\n modulesDir: string\n noEntity?: boolean\n noTests?: boolean\n repo?: 'drizzle' | 'inmemory'\n minimal?: boolean\n}\n\n/**\n * Generate a full DDD module with all layers:\n * presentation/ — controller\n * application/ — use-cases, DTOs\n * domain/ — entity, value objects, repository interface, domain service\n * infrastructure/ — repository implementation\n */\nexport async function generateModule(options: GenerateModuleOptions): Promise<string[]> {\n const { name, modulesDir, noEntity, noTests, repo = 'inmemory', minimal } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const camel = toCamelCase(name)\n const plural = pluralize(kebab)\n const pluralPascal = pluralizePascal(pascal)\n const moduleDir = join(modulesDir, plural)\n\n const files: string[] = []\n\n const write = async (relativePath: string, content: string) => {\n const fullPath = join(moduleDir, relativePath)\n await writeFileSafe(fullPath, content)\n files.push(fullPath)\n }\n\n // ── Module Index ────────────────────────────────────────────────────\n await write(\n 'index.ts',\n `/**\n * ${pascal} Module\n *\n * Self-contained feature module following Domain-Driven Design (DDD).\n * Registers dependencies in the DI container and declares HTTP routes.\n *\n * Structure:\n * presentation/ — HTTP controllers (entry points)\n * application/ — Use cases (orchestration) and DTOs (validation)\n * domain/ — Entities, value objects, repository interfaces, domain services\n * infrastructure/ — Repository implementations (in-memory, Drizzle, Prisma, etc.)\n */\nimport { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs-core'\nimport { buildRoutes } from '@forinda/kickjs-http'\nimport { ${pascal.toUpperCase()}_REPOSITORY } from './domain/repositories/${kebab}.repository'\nimport { ${repo === 'inmemory' ? `InMemory${pascal}Repository` : `Drizzle${pascal}Repository`} } from './infrastructure/repositories/${repo === 'inmemory' ? `in-memory-${kebab}` : `drizzle-${kebab}`}.repository'\nimport { ${pascal}Controller } from './presentation/${kebab}.controller'\n\n// Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container\nimport.meta.glob(\n ['./domain/services/**/*.ts', './application/use-cases/**/*.ts', '!./**/*.test.ts'],\n { eager: true },\n)\n\nexport class ${pascal}Module implements AppModule {\n /**\n * Register module dependencies in the DI container.\n * Bind repository interface tokens to their implementations here.\n * To swap implementations (e.g. in-memory -> Drizzle), change the factory target.\n */\n register(container: Container): void {\n container.registerFactory(${pascal.toUpperCase()}_REPOSITORY, () =>\n container.resolve(${repo === 'inmemory' ? `InMemory${pascal}Repository` : `Drizzle${pascal}Repository`}),\n )\n }\n\n /**\n * Declare HTTP routes for this module.\n * The path is prefixed with the global apiPrefix and version (e.g. /api/v1/${plural}).\n * Passing 'controller' enables automatic OpenAPI spec generation via SwaggerAdapter.\n */\n routes(): ModuleRoutes {\n return {\n path: '/${plural}',\n router: buildRoutes(${pascal}Controller),\n controller: ${pascal}Controller,\n }\n }\n}\n`,\n )\n\n // ── Controller ──────────────────────────────────────────────────────\n await write(\n `presentation/${kebab}.controller.ts`,\n `/**\n * ${pascal} Controller\n *\n * Presentation layer — handles HTTP requests and delegates to use cases.\n * Each method receives a RequestContext with typed body, params, and query.\n *\n * Decorators:\n * @Controller(path?) — registers this class as an HTTP controller\n * @Get/@Post/@Put/@Delete(path?, validation?) — defines routes with optional Zod validation\n * @Autowired() — injects dependencies lazily from the DI container\n * @Middleware(...handlers) — attach middleware at class or method level\n *\n * Add Swagger decorators (@ApiTags, @ApiOperation, @ApiResponse) from @forinda/kickjs-swagger\n * for automatic OpenAPI documentation.\n */\nimport { Controller, Get, Post, Put, Delete, Autowired } from '@forinda/kickjs-core'\nimport { RequestContext } from '@forinda/kickjs-http'\nimport { Create${pascal}UseCase } from '../application/use-cases/create-${kebab}.use-case'\nimport { Get${pascal}UseCase } from '../application/use-cases/get-${kebab}.use-case'\nimport { List${pluralPascal}UseCase } from '../application/use-cases/list-${plural}.use-case'\nimport { Update${pascal}UseCase } from '../application/use-cases/update-${kebab}.use-case'\nimport { Delete${pascal}UseCase } from '../application/use-cases/delete-${kebab}.use-case'\nimport { create${pascal}Schema } from '../application/dtos/create-${kebab}.dto'\nimport { update${pascal}Schema } from '../application/dtos/update-${kebab}.dto'\n\n@Controller()\nexport class ${pascal}Controller {\n @Autowired() private create${pascal}UseCase!: Create${pascal}UseCase\n @Autowired() private get${pascal}UseCase!: Get${pascal}UseCase\n @Autowired() private list${pluralPascal}UseCase!: List${pluralPascal}UseCase\n @Autowired() private update${pascal}UseCase!: Update${pascal}UseCase\n @Autowired() private delete${pascal}UseCase!: Delete${pascal}UseCase\n\n @Post('/', { body: create${pascal}Schema })\n async create(ctx: RequestContext) {\n const result = await this.create${pascal}UseCase.execute(ctx.body)\n ctx.created(result)\n }\n\n @Get('/')\n async list(ctx: RequestContext) {\n const result = await this.list${pluralPascal}UseCase.execute()\n ctx.json(result)\n }\n\n @Get('/:id')\n async getById(ctx: RequestContext) {\n const result = await this.get${pascal}UseCase.execute(ctx.params.id)\n if (!result) return ctx.notFound('${pascal} not found')\n ctx.json(result)\n }\n\n @Put('/:id', { body: update${pascal}Schema })\n async update(ctx: RequestContext) {\n const result = await this.update${pascal}UseCase.execute(ctx.params.id, ctx.body)\n ctx.json(result)\n }\n\n @Delete('/:id')\n async remove(ctx: RequestContext) {\n await this.delete${pascal}UseCase.execute(ctx.params.id)\n ctx.noContent()\n }\n}\n`,\n )\n\n // ── DTOs ────────────────────────────────────────────────────────────\n await write(\n `application/dtos/create-${kebab}.dto.ts`,\n `import { z } from 'zod'\n\n/**\n * Create ${pascal} DTO — Zod schema for validating POST request bodies.\n * This schema is passed to @Post('/', { body: create${pascal}Schema }) for automatic validation.\n * It also generates OpenAPI request body docs when SwaggerAdapter is used.\n *\n * Add more fields as needed. Supported Zod types:\n * z.string(), z.number(), z.boolean(), z.enum([...]),\n * z.array(), z.object(), .optional(), .default(), .transform()\n */\nexport const create${pascal}Schema = z.object({\n name: z.string().min(1, 'Name is required').max(200),\n})\n\nexport type Create${pascal}DTO = z.infer<typeof create${pascal}Schema>\n`,\n )\n\n await write(\n `application/dtos/update-${kebab}.dto.ts`,\n `import { z } from 'zod'\n\nexport const update${pascal}Schema = z.object({\n name: z.string().min(1).max(200).optional(),\n})\n\nexport type Update${pascal}DTO = z.infer<typeof update${pascal}Schema>\n`,\n )\n\n await write(\n `application/dtos/${kebab}-response.dto.ts`,\n `export interface ${pascal}ResponseDTO {\n id: string\n name: string\n createdAt: string\n updatedAt: string\n}\n`,\n )\n\n // ── Use Cases ───────────────────────────────────────────────────────\n const useCases = [\n {\n file: `create-${kebab}.use-case.ts`,\n content: `/**\n * Create ${pascal} Use Case\n *\n * Application layer — orchestrates a single business operation.\n * Use cases are thin: validate input (via DTO), call domain/repo, return response.\n * Keep business rules in the domain service, not here.\n */\nimport { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { Create${pascal}DTO } from '../dtos/create-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Create${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.create(dto)\n }\n}\n`,\n },\n {\n file: `get-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Get${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.repo.findById(id)\n }\n}\n`,\n },\n {\n file: `list-${plural}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class List${pluralPascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(): Promise<${pascal}ResponseDTO[]> {\n return this.repo.findAll()\n }\n}\n`,\n },\n {\n file: `update-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { Update${pascal}DTO } from '../dtos/update-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Update${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.update(id, dto)\n }\n}\n`,\n },\n {\n file: `delete-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\n\n@Service()\nexport class Delete${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string): Promise<void> {\n await this.repo.delete(id)\n }\n}\n`,\n },\n ]\n\n for (const uc of useCases) {\n await write(`application/use-cases/${uc.file}`, uc.content)\n }\n\n // ── Domain: Repository Interface ────────────────────────────────────\n await write(\n `domain/repositories/${kebab}.repository.ts`,\n `/**\n * ${pascal} Repository Interface\n *\n * Domain layer — defines the contract for data access.\n * The interface lives in the domain layer; implementations live in infrastructure.\n * This inversion of dependencies keeps the domain pure and testable.\n *\n * To swap implementations (e.g. in-memory -> Drizzle -> Prisma),\n * change the factory in the module's register() method.\n */\nimport type { ${pascal}ResponseDTO } from '../../application/dtos/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '../../application/dtos/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '../../application/dtos/update-${kebab}.dto'\n\nexport interface I${pascal}Repository {\n findById(id: string): Promise<${pascal}ResponseDTO | null>\n findAll(): Promise<${pascal}ResponseDTO[]>\n create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO>\n update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO>\n delete(id: string): Promise<void>\n}\n\nexport const ${pascal.toUpperCase()}_REPOSITORY = Symbol('I${pascal}Repository')\n`,\n )\n\n // ── Domain: Service ─────────────────────────────────────────────────\n await write(\n `domain/services/${kebab}-domain.service.ts`,\n `/**\n * ${pascal} Domain Service\n *\n * Domain layer — contains business rules that don't belong to a single entity.\n * Use this for cross-entity logic, validation rules, and domain invariants.\n * Keep it free of HTTP/framework concerns.\n */\nimport { Service, Inject, HttpException } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../repositories/${kebab}.repository'\n\n@Service()\nexport class ${pascal}DomainService {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async ensureExists(id: string): Promise<void> {\n const entity = await this.repo.findById(id)\n if (!entity) {\n throw HttpException.notFound('${pascal} not found')\n }\n }\n}\n`,\n )\n\n // ── Infrastructure: Repository Implementation ──────────────────────\n if (repo === 'inmemory') {\n await write(\n `infrastructure/repositories/in-memory-${kebab}.repository.ts`,\n `/**\n * In-Memory ${pascal} Repository\n *\n * Infrastructure layer — implements the repository interface using a Map.\n * Useful for prototyping and testing. Replace with a database implementation\n * (Drizzle, Prisma, etc.) for production use.\n *\n * @Repository() registers this class in the DI container as a singleton.\n */\nimport { randomUUID } from 'node:crypto'\nimport { Repository, HttpException } from '@forinda/kickjs-core'\nimport type { I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../../application/dtos/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '../../application/dtos/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '../../application/dtos/update-${kebab}.dto'\n\n@Repository()\nexport class InMemory${pascal}Repository implements I${pascal}Repository {\n private store = new Map<string, ${pascal}ResponseDTO>()\n\n async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.store.get(id) ?? null\n }\n\n async findAll(): Promise<${pascal}ResponseDTO[]> {\n return Array.from(this.store.values())\n }\n\n async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const now = new Date().toISOString()\n const entity: ${pascal}ResponseDTO = {\n id: randomUUID(),\n name: dto.name,\n createdAt: now,\n updatedAt: now,\n }\n this.store.set(entity.id, entity)\n return entity\n }\n\n async update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const existing = this.store.get(id)\n if (!existing) throw HttpException.notFound('${pascal} not found')\n const updated = { ...existing, ...dto, updatedAt: new Date().toISOString() }\n this.store.set(id, updated)\n return updated\n }\n\n async delete(id: string): Promise<void> {\n if (!this.store.has(id)) throw HttpException.notFound('${pascal} not found')\n this.store.delete(id)\n }\n}\n`,\n )\n }\n\n // ── Entity & Value Objects ──────────────────────────────────────────\n if (!noEntity && !minimal) {\n await write(\n `domain/entities/${kebab}.entity.ts`,\n `/**\n * ${pascal} Entity\n *\n * Domain layer — the core business object.\n * Uses a private constructor with static factory methods (create, reconstitute)\n * to enforce invariants. Properties are accessed via getters to maintain encapsulation.\n *\n * Patterns used:\n * - Private constructor: prevents direct instantiation\n * - create(): factory for new entities (generates ID, sets timestamps)\n * - reconstitute(): factory for rebuilding from persistence (no side effects)\n * - changeName(): mutation method that enforces business rules\n */\nimport { ${pascal}Id } from '../value-objects/${kebab}-id.vo'\n\ninterface ${pascal}Props {\n id: ${pascal}Id\n name: string\n createdAt: Date\n updatedAt: Date\n}\n\nexport class ${pascal} {\n private constructor(private props: ${pascal}Props) {}\n\n static create(params: { name: string }): ${pascal} {\n const now = new Date()\n return new ${pascal}({\n id: ${pascal}Id.create(),\n name: params.name,\n createdAt: now,\n updatedAt: now,\n })\n }\n\n static reconstitute(props: ${pascal}Props): ${pascal} {\n return new ${pascal}(props)\n }\n\n get id(): ${pascal}Id {\n return this.props.id\n }\n get name(): string {\n return this.props.name\n }\n get createdAt(): Date {\n return this.props.createdAt\n }\n get updatedAt(): Date {\n return this.props.updatedAt\n }\n\n changeName(name: string): void {\n if (!name || name.trim().length === 0) {\n throw new Error('Name cannot be empty')\n }\n this.props.name = name.trim()\n this.props.updatedAt = new Date()\n }\n\n toJSON() {\n return {\n id: this.props.id.toString(),\n name: this.props.name,\n createdAt: this.props.createdAt.toISOString(),\n updatedAt: this.props.updatedAt.toISOString(),\n }\n }\n}\n`,\n )\n\n await write(\n `domain/value-objects/${kebab}-id.vo.ts`,\n `/**\n * ${pascal} ID Value Object\n *\n * Domain layer — wraps a primitive ID with type safety and validation.\n * Value objects are immutable and compared by value, not reference.\n *\n * ${pascal}Id.create() — generate a new UUID\n * ${pascal}Id.from(id) — wrap an existing ID string (validates non-empty)\n * id.equals(other) — compare two IDs by value\n */\nimport { randomUUID } from 'node:crypto'\n\nexport class ${pascal}Id {\n private constructor(private readonly value: string) {}\n\n static create(): ${pascal}Id {\n return new ${pascal}Id(randomUUID())\n }\n\n static from(id: string): ${pascal}Id {\n if (!id || id.trim().length === 0) {\n throw new Error('${pascal}Id cannot be empty')\n }\n return new ${pascal}Id(id)\n }\n\n toString(): string {\n return this.value\n }\n\n equals(other: ${pascal}Id): boolean {\n return this.value === other.value\n }\n}\n`,\n )\n }\n\n // ── Auto-register in modules index ──────────────────────────────────\n await autoRegisterModule(modulesDir, pascal, plural)\n\n return files\n}\n\n/** Add the new module to src/modules/index.ts */\nasync function autoRegisterModule(\n modulesDir: string,\n pascal: string,\n plural: string,\n): Promise<void> {\n const indexPath = join(modulesDir, 'index.ts')\n const exists = await fileExists(indexPath)\n\n if (!exists) {\n await writeFileSafe(\n indexPath,\n `import type { AppModuleClass } from '@forinda/kickjs-core'\nimport { ${pascal}Module } from './${plural}'\n\nexport const modules: AppModuleClass[] = [${pascal}Module]\n`,\n )\n return\n }\n\n let content = await readFile(indexPath, 'utf-8')\n\n // Add import if not present\n const importLine = `import { ${pascal}Module } from './${plural}'`\n if (!content.includes(`${pascal}Module`)) {\n // Insert import after last existing import\n const lastImportIdx = content.lastIndexOf('import ')\n if (lastImportIdx !== -1) {\n const lineEnd = content.indexOf('\\n', lastImportIdx)\n content = content.slice(0, lineEnd + 1) + importLine + '\\n' + content.slice(lineEnd + 1)\n } else {\n content = importLine + '\\n' + content\n }\n\n // Add to modules array — handle both empty and existing entries\n // Match the array assignment: `= [...]` or `= [\\n...\\n]`\n content = content.replace(/(=\\s*\\[)([\\s\\S]*?)(])/, (_match, open, existing, close) => {\n const trimmed = existing.trim()\n if (!trimmed) {\n // Empty array: `= []`\n return `${open}${pascal}Module${close}`\n }\n // Existing entries: append with comma\n const needsComma = trimmed.endsWith(',') ? '' : ','\n return `${open}${existing.trimEnd()}${needsComma} ${pascal}Module${close}`\n })\n }\n\n await writeFile(indexPath, content, 'utf-8')\n}\n","/** Convert a name to PascalCase */\nexport function toPascalCase(name: string): string {\n return name\n .replace(/[-_\\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))\n .replace(/^(.)/, (c) => c.toUpperCase())\n}\n\n/** Convert a name to camelCase */\nexport function toCamelCase(name: string): string {\n const pascal = toPascalCase(name)\n return pascal.charAt(0).toLowerCase() + pascal.slice(1)\n}\n\n/** Convert a name to kebab-case */\nexport function toKebabCase(name: string): string {\n return name\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\n\n/**\n * Pluralize a kebab-case name for directory/file names.\n * If already plural (ends in 's'), returns as-is.\n */\nexport function pluralize(name: string): string {\n if (name.endsWith('s')) return name\n if (name.endsWith('x') || name.endsWith('z')) return name + 'es'\n if (name.endsWith('sh') || name.endsWith('ch')) return name + 'es'\n if (name.endsWith('y') && !/[aeiou]y$/.test(name)) return name.slice(0, -1) + 'ies'\n return name + 's'\n}\n\n/**\n * Pluralize a PascalCase name for class identifiers.\n * If already plural (ends in 's'), returns as-is.\n * Used for `List${pluralPascal}UseCase` to avoid `ListUserssUseCase`.\n */\nexport function pluralizePascal(name: string): string {\n if (name.endsWith('s')) return name\n if (name.endsWith('x') || name.endsWith('z')) return name + 'es'\n if (name.endsWith('sh') || name.endsWith('ch')) return name + 'es'\n if (name.endsWith('y') && !/[aeiou]y$/i.test(name)) return name.slice(0, -1) + 'ies'\n return name + 's'\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateAdapterOptions {\n name: string\n outDir: string\n}\n\nexport async function generateAdapter(options: GenerateAdapterOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.adapter.ts`)\n await writeFileSafe(\n filePath,\n `import type { Express } from 'express'\nimport type { AppAdapter, AdapterMiddleware, Container } from '@forinda/kickjs-core'\n\nexport interface ${pascal}AdapterOptions {\n // Add your adapter configuration here\n}\n\n/**\n * ${pascal} adapter.\n *\n * Hooks into the Application lifecycle to add middleware, routes,\n * or external service connections.\n *\n * Usage:\n * bootstrap({\n * adapters: [new ${pascal}Adapter({ ... })],\n * })\n */\nexport class ${pascal}Adapter implements AppAdapter {\n name = '${pascal}Adapter'\n\n constructor(private options: ${pascal}AdapterOptions = {}) {}\n\n /**\n * Return middleware entries that the Application will mount.\n * Use \\`phase\\` to control where in the pipeline they run:\n * 'beforeGlobal' | 'afterGlobal' | 'beforeRoutes' | 'afterRoutes'\n */\n middleware(): AdapterMiddleware[] {\n return [\n // Example: add a custom header to all responses\n // {\n // phase: 'beforeGlobal',\n // handler: (_req: any, res: any, next: any) => {\n // res.setHeader('X-${pascal}', 'true')\n // next()\n // },\n // },\n // Example: scope middleware to a specific path\n // {\n // phase: 'beforeRoutes',\n // path: '/api/v1/admin',\n // handler: myAdminMiddleware(),\n // },\n ]\n }\n\n /**\n * Called before global middleware.\n * Use this to mount routes that bypass the middleware stack\n * (health checks, docs UI, static assets).\n */\n beforeMount(app: Express, container: Container): void {\n // Example: mount a status route\n // app.get('/${kebab}/status', (_req, res) => {\n // res.json({ status: 'ok' })\n // })\n }\n\n /**\n * Called after modules and routes are registered, before the server starts.\n * Use this for late-stage DI registrations or config validation.\n */\n beforeStart(app: Express, container: Container): void {\n // Example: register a service in the DI container\n // container.registerInstance(MY_TOKEN, new MyService(this.options))\n }\n\n /**\n * Called after the HTTP server is listening.\n * Use this to attach to the raw http.Server (Socket.IO, gRPC, etc).\n */\n afterStart(server: any, container: Container): void {\n // Example: attach Socket.IO\n // const io = new Server(server)\n // container.registerInstance(SOCKET_IO, io)\n }\n\n /**\n * Called on graceful shutdown. Clean up connections.\n */\n async shutdown(): Promise<void> {\n // Example: close a connection pool\n // await this.pool.end()\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\n\ninterface GenerateMiddlewareOptions {\n name: string\n outDir: string\n}\n\nexport async function generateMiddleware(options: GenerateMiddlewareOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const camel = toCamelCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.middleware.ts`)\n await writeFileSafe(\n filePath,\n `import type { Request, Response, NextFunction } from 'express'\n\nexport interface ${toPascalCase(name)}Options {\n // Add configuration options here\n}\n\n/**\n * ${toPascalCase(name)} middleware.\n *\n * Usage in bootstrap:\n * middleware: [${camel}()]\n *\n * Usage with adapter:\n * middleware() { return [{ handler: ${camel}(), phase: 'afterGlobal' }] }\n *\n * Usage with @Middleware decorator:\n * @Middleware(${camel}())\n */\nexport function ${camel}(options: ${toPascalCase(name)}Options = {}) {\n return (req: Request, res: Response, next: NextFunction) => {\n // Implement your middleware logic here\n next()\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\n\ninterface GenerateGuardOptions {\n name: string\n outDir: string\n}\n\nexport async function generateGuard(options: GenerateGuardOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const camel = toCamelCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.guard.ts`)\n await writeFileSafe(\n filePath,\n `import { Container, HttpException } from '@forinda/kickjs-core'\nimport type { RequestContext } from '@forinda/kickjs-http'\n\n/**\n * ${pascal} guard.\n *\n * Guards protect routes by checking conditions before the handler runs.\n * Return early with an error response to block access.\n *\n * Usage:\n * @Middleware(${camel}Guard)\n * @Get('/protected')\n * async handler(ctx: RequestContext) { ... }\n */\nexport async function ${camel}Guard(ctx: RequestContext, next: () => void): Promise<void> {\n // Example: check for an authorization header\n const header = ctx.headers.authorization\n if (!header?.startsWith('Bearer ')) {\n ctx.res.status(401).json({ message: 'Missing or invalid authorization header' })\n return\n }\n\n const token = header.slice(7)\n\n try {\n // Verify the token using a service from the DI container\n // const container = Container.getInstance()\n // const authService = container.resolve(AuthService)\n // const payload = authService.verifyToken(token)\n // ctx.set('auth', payload)\n\n next()\n } catch {\n ctx.res.status(401).json({ message: 'Invalid or expired token' })\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateServiceOptions {\n name: string\n outDir: string\n}\n\nexport async function generateService(options: GenerateServiceOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.service.ts`)\n await writeFileSafe(\n filePath,\n `import { Service } from '@forinda/kickjs-core'\n\n@Service()\nexport class ${pascal}Service {\n // Inject dependencies via constructor\n // constructor(\n // @Inject(MY_REPO) private readonly repo: IMyRepository,\n // ) {}\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateControllerOptions {\n name: string\n outDir: string\n}\n\nexport async function generateController(options: GenerateControllerOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.controller.ts`)\n await writeFileSafe(\n filePath,\n `import { Controller, Get, Post, Autowired } from '@forinda/kickjs-core'\nimport type { RequestContext } from '@forinda/kickjs-http'\n\n@Controller()\nexport class ${pascal}Controller {\n // @Autowired() private myService!: MyService\n\n @Get('/')\n async list(ctx: RequestContext) {\n ctx.json({ message: '${pascal} list' })\n }\n\n @Post('/')\n async create(ctx: RequestContext) {\n ctx.created({ message: '${pascal} created', data: ctx.body })\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\n\ninterface GenerateDtoOptions {\n name: string\n outDir: string\n}\n\nexport async function generateDto(options: GenerateDtoOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const camel = toCamelCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.dto.ts`)\n await writeFileSafe(\n filePath,\n `import { z } from 'zod'\n\nexport const ${camel}Schema = z.object({\n // Define your schema fields here\n name: z.string().min(1).max(200),\n})\n\nexport type ${pascal}DTO = z.infer<typeof ${camel}Schema>\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport { createInterface } from 'node:readline'\nimport { writeFileSafe } from '../utils/fs'\n\ninterface GenerateConfigOptions {\n outDir: string\n modulesDir?: string\n defaultRepo?: string\n force?: boolean\n}\n\nasync function confirm(message: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stdout })\n return new Promise((resolve) => {\n rl.question(` ${message} (y/N) `, (answer) => {\n rl.close()\n resolve(answer.trim().toLowerCase() === 'y')\n })\n })\n}\n\nexport async function generateConfig(options: GenerateConfigOptions): Promise<string[]> {\n const filePath = join(options.outDir, 'kick.config.ts')\n const modulesDir = options.modulesDir ?? 'src/modules'\n const defaultRepo = options.defaultRepo ?? 'inmemory'\n\n if (existsSync(filePath) && !options.force) {\n const overwrite = await confirm('kick.config.ts already exists. Overwrite?')\n if (!overwrite) {\n console.log('\\n Skipped — existing kick.config.ts preserved.')\n return []\n }\n }\n\n await writeFileSafe(\n filePath,\n `import { defineConfig } from '@forinda/kickjs-cli'\n\nexport default defineConfig({\n modulesDir: '${modulesDir}',\n defaultRepo: '${defaultRepo}',\n\n commands: [\n {\n name: 'test',\n description: 'Run tests with Vitest',\n steps: 'npx vitest run',\n },\n {\n name: 'format',\n description: 'Format code with Prettier',\n steps: 'npx prettier --write src/',\n },\n {\n name: 'format:check',\n description: 'Check formatting without writing',\n steps: 'npx prettier --check src/',\n },\n {\n name: 'check',\n description: 'Run typecheck + format check',\n steps: ['npx tsc --noEmit', 'npx prettier --check src/'],\n aliases: ['verify', 'ci'],\n },\n ],\n})\n`,\n )\n\n return [filePath]\n}\n","import { execSync } from 'node:child_process'\n\n/** Run a shell command synchronously, printing output */\nexport function runShellCommand(command: string, cwd?: string): void {\n execSync(command, {\n cwd,\n stdio: 'inherit',\n })\n}\n","import type { Command } from 'commander'\nimport { runShellCommand } from '../utils/shell'\n\nexport function registerRunCommands(program: Command): void {\n program\n .command('dev')\n .description('Start development server with Vite HMR (zero-downtime reload)')\n .option('-e, --entry <file>', 'Entry file', 'src/index.ts')\n .option('-p, --port <port>', 'Port number')\n .action((opts: any) => {\n const envVars: string[] = []\n if (opts.port) envVars.push(`PORT=${opts.port}`)\n\n // vite-node --watch gives true HMR via import.meta.hot.accept()\n // The Application.rebuild() swaps the Express handler on the existing\n // http.Server — DB, Redis, Socket.IO connections survive across reloads\n const cmd = `npx vite-node --watch ${opts.entry}`\n const fullCmd = envVars.length ? `${envVars.join(' ')} ${cmd}` : cmd\n\n console.log(`\\n KickJS dev server starting...`)\n console.log(` Entry: ${opts.entry}`)\n console.log(` HMR: enabled (vite-node)\\n`)\n\n try {\n runShellCommand(fullCmd)\n } catch {\n // Process exits on SIGINT — expected\n }\n })\n\n program\n .command('build')\n .description('Build for production via Vite')\n .action(() => {\n console.log('\\n Building for production...\\n')\n runShellCommand('npx vite build')\n })\n\n program\n .command('start')\n .description('Start production server')\n .option('-e, --entry <file>', 'Entry file', 'dist/index.js')\n .option('-p, --port <port>', 'Port number')\n .action((opts: any) => {\n const envVars: string[] = ['NODE_ENV=production']\n if (opts.port) envVars.push(`PORT=${opts.port}`)\n runShellCommand(`${envVars.join(' ')} node ${opts.entry}`)\n })\n\n program\n .command('dev:debug')\n .description('Start dev server with Node.js inspector')\n .option('-e, --entry <file>', 'Entry file', 'src/index.ts')\n .option('-p, --port <port>', 'Port number')\n .action((opts: any) => {\n const envVars = opts.port ? `PORT=${opts.port} ` : ''\n try {\n runShellCommand(`${envVars}npx vite-node --inspect --watch ${opts.entry}`)\n } catch {\n // SIGINT\n }\n })\n}\n","import { platform, release, arch } from 'node:os'\nimport type { Command } from 'commander'\n\nexport function registerInfoCommand(program: Command): void {\n program\n .command('info')\n .description('Print system and framework info')\n .action(() => {\n console.log(`\n KickJS CLI\n\n System:\n OS: ${platform()} ${release()} (${arch()})\n Node: ${process.version}\n\n Packages:\n @forinda/kickjs-core workspace\n @forinda/kickjs-http workspace\n @forinda/kickjs-config workspace\n @forinda/kickjs-cli workspace\n`)\n })\n}\n","import type { Command } from 'commander'\nimport type { KickConfig, KickCommandDefinition } from '../config'\nimport { runShellCommand } from '../utils/shell'\n\n/**\n * Register custom commands defined in kick.config.ts\n *\n * Developers can extend the CLI with project-specific commands like:\n * kick db:migrate\n * kick db:generate\n * kick seed\n * kick proto:gen\n *\n * @example kick.config.ts\n * ```ts\n * import { defineConfig } from '@forinda/kickjs-cli'\n *\n * export default defineConfig({\n * commands: [\n * {\n * name: 'db:generate',\n * description: 'Generate Drizzle migrations from schema',\n * steps: 'npx drizzle-kit generate',\n * },\n * {\n * name: 'db:migrate',\n * description: 'Run database migrations',\n * steps: 'npx drizzle-kit migrate',\n * },\n * {\n * name: 'db:push',\n * description: 'Push schema directly (dev only)',\n * steps: 'npx drizzle-kit push',\n * },\n * {\n * name: 'db:studio',\n * description: 'Open Drizzle Studio GUI',\n * steps: 'npx drizzle-kit studio',\n * },\n * {\n * name: 'db:seed',\n * description: 'Run seed files',\n * steps: 'npx tsx src/db/seed.ts',\n * },\n * {\n * name: 'proto:gen',\n * description: 'Generate TypeScript from protobuf definitions',\n * steps: [\n * 'npx buf generate',\n * 'echo \"Protobuf types generated\"',\n * ],\n * },\n * ],\n * })\n * ```\n */\nexport function registerCustomCommands(program: Command, config: KickConfig | null): void {\n if (!config?.commands?.length) return\n\n for (const cmd of config.commands) {\n registerSingleCommand(program, cmd)\n }\n}\n\nfunction registerSingleCommand(program: Command, def: KickCommandDefinition): void {\n const command = program.command(def.name).description(def.description)\n\n if (def.aliases) {\n for (const alias of def.aliases) {\n command.alias(alias)\n }\n }\n\n // Accept arbitrary trailing arguments\n command.allowUnknownOption(true)\n command.argument('[args...]', 'Additional arguments passed to the command')\n\n command.action((args: string[]) => {\n const extraArgs = args.join(' ')\n const steps = Array.isArray(def.steps) ? def.steps : [def.steps]\n\n for (const step of steps) {\n // Replace {args} placeholder with CLI arguments\n const finalCmd = extraArgs ? `${step} ${extraArgs}` : step\n console.log(` $ ${finalCmd}`)\n try {\n runShellCommand(finalCmd)\n } catch (err: any) {\n console.error(` Command failed: ${def.name}`)\n process.exitCode = 1\n return\n }\n }\n })\n}\n","import { readFile, access } from 'node:fs/promises'\nimport { join } from 'node:path'\n\n/** A custom command that developers can register via kick.config.ts */\nexport interface KickCommandDefinition {\n /** The command name (e.g. 'db:migrate', 'seed', 'proto:gen') */\n name: string\n /** Description shown in --help */\n description: string\n /**\n * Shell command(s) to run. Can be a single string or an array of\n * sequential steps. Use {args} as a placeholder for CLI arguments.\n *\n * @example\n * 'npx drizzle-kit migrate'\n * ['npx drizzle-kit generate', 'npx drizzle-kit migrate']\n */\n steps: string | string[]\n /** Optional aliases (e.g. ['migrate'] for 'db:migrate') */\n aliases?: string[]\n}\n\n/** Configuration for the kick.config.ts file */\nexport interface KickConfig {\n /** Where modules live (default: 'src/modules') */\n modulesDir?: string\n /** Default repository implementation for generators */\n defaultRepo?: 'drizzle' | 'inmemory' | 'prisma'\n /** Drizzle schema output directory */\n schemaDir?: string\n /** Custom commands that extend the CLI */\n commands?: KickCommandDefinition[]\n /** Code style overrides (auto-detected from prettier when possible) */\n style?: {\n semicolons?: boolean\n quotes?: 'single' | 'double'\n trailingComma?: 'all' | 'es5' | 'none'\n indent?: number\n }\n}\n\n/** Helper to define a type-safe kick.config.ts */\nexport function defineConfig(config: KickConfig): KickConfig {\n return config\n}\n\nconst CONFIG_FILES = ['kick.config.ts', 'kick.config.js', 'kick.config.mjs', 'kick.config.json']\n\n/** Load kick.config.* from the project root */\nexport async function loadKickConfig(cwd: string): Promise<KickConfig | null> {\n for (const filename of CONFIG_FILES) {\n const filepath = join(cwd, filename)\n try {\n await access(filepath)\n } catch {\n continue\n }\n\n if (filename.endsWith('.json')) {\n const content = await readFile(filepath, 'utf-8')\n return JSON.parse(content)\n }\n\n // For .ts/.js/.mjs — dynamic import (use file URL for cross-platform compat)\n try {\n const { pathToFileURL } = await import('node:url')\n const mod = await import(pathToFileURL(filepath).href)\n return mod.default ?? mod\n } catch (err) {\n if (filename.endsWith('.ts')) {\n console.warn(\n `Warning: Failed to load ${filename}. TypeScript config files require ` +\n 'a runtime loader (e.g. tsx, ts-node) or use kick.config.js/.mjs instead.',\n )\n }\n continue\n }\n }\n return null\n}\n"],"mappings":";;;;;AAAA,SAASA,eAAe;;;ACAxB,SAASC,SAASC,gBAAgB;AAClC,SAASC,uBAAuB;AAChC,SAASC,YAAYC,aAAaC,cAAc;;;ACFhD,SAASC,YAAY;AACrB,SAASC,gBAAgB;;;ACDzB,SAASC,WAAWC,OAAOC,QAAQC,gBAAgB;AACnD,SAASC,eAAe;AAGxB,eAAsBC,cAAcC,UAAkBC,SAAe;AACnE,QAAMC,MAAMC,QAAQH,QAAAA,GAAW;IAAEI,WAAW;EAAK,CAAA;AACjD,QAAMC,UAAUL,UAAUC,SAAS,OAAA;AACrC;AAHsBF;AAWtB,eAAsBO,WAAWC,UAAgB;AAC/C,MAAI;AACF,UAAMC,OAAOD,QAAAA;AACb,WAAO;EACT,QAAQ;AACN,WAAO;EACT;AACF;AAPsBD;;;ADFtB,eAAsBG,YAAYC,SAA2B;AAC3D,QAAM,EAAEC,MAAMC,WAAWC,iBAAiB,OAAM,IAAKH;AACrD,QAAMI,MAAMF;AAEZG,UAAQC,IAAI;6BAAgCL,IAAAA;CAAQ;AAGpD,QAAMM,cACJC,KAAKJ,KAAK,cAAA,GACVK,KAAKC,UACH;IACET;IACAU,SAAS;IACTC,MAAM;IACNC,SAAS;MACPC,KAAK;MACL,aAAa;MACbC,OAAO;MACPC,OAAO;MACPC,MAAM;MACN,cAAc;MACdC,WAAW;MACXC,MAAM;MACNC,QAAQ;IACV;IACAC,cAAc;MACZ,wBAAwB;MACxB,wBAAwB;MACxB,0BAA0B;MAC1B,2BAA2B;MAC3BC,SAAS;MACT,oBAAoB;MACpBC,KAAK;MACLC,MAAM;MACN,eAAe;IACjB;IACAC,iBAAiB;MACf,uBAAuB;MACvB,aAAa;MACb,kBAAkB;MAClB,eAAe;MACf,gBAAgB;MAChBC,MAAM;MACN,aAAa;MACbC,QAAQ;MACRC,YAAY;MACZC,UAAU;IACZ;EACF,GACA,MACA,CAAA,CAAA;AAKJ,QAAMtB,cACJC,KAAKJ,KAAK,gBAAA,GACV;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BH;AAIC,QAAMG,cACJC,KAAKJ,KAAK,eAAA,GACVK,KAAKC,UACH;IACEoB,iBAAiB;MACfC,QAAQ;MACRC,QAAQ;MACRC,kBAAkB;MAClBC,KAAK;QAAC;;MACNC,OAAO;QAAC;;MACRC,QAAQ;MACRC,iBAAiB;MACjBC,cAAc;MACdC,WAAW;MACXC,aAAa;MACbC,wBAAwB;MACxBC,uBAAuB;MACvBC,QAAQ;MACRC,SAAS;MACTC,OAAO;QAAE,OAAO;UAAC;;MAAW;IAC9B;IACAC,SAAS;MAAC;;EACZ,GACA,MACA,CAAA,CAAA;AAKJ,QAAMvC,cACJC,KAAKJ,KAAK,aAAA,GACVK,KAAKC,UACH;IACEqC,MAAM;IACNC,aAAa;IACbC,eAAe;IACfC,YAAY;IACZC,UAAU;EACZ,GACA,MACA,CAAA,CAAA;AAKJ,QAAM5C,cACJC,KAAKJ,KAAK,YAAA,GACV;;;;;;CAMH;AAIC,QAAMG,cACJC,KAAKJ,KAAK,MAAA,GACV;;CAEH;AAGC,QAAMG,cACJC,KAAKJ,KAAK,cAAA,GACV;;CAEH;AAIC,QAAMG,cACJC,KAAKJ,KAAK,cAAA,GACV;;;;;;;;;wBASoBH,IAAAA;;;;CAIvB;AAIC,QAAMM,cACJC,KAAKJ,KAAK,sBAAA,GACV;;;CAGH;AAIC,QAAMG,cACJC,KAAKJ,KAAK,gBAAA,GACV;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BH;AAIC,QAAMG,cACJC,KAAKJ,KAAK,kBAAA,GACV;;;;;;;;;;;CAWH;AAIC,MAAIJ,QAAQoD,SAAS;AACnB,QAAI;AACFC,eAAS,YAAY;QAAEC,KAAKlD;QAAKmD,OAAO;MAAO,CAAA;AAC/CF,eAAS,cAAc;QAAEC,KAAKlD;QAAKmD,OAAO;MAAO,CAAA;AACjDF,eAAS,uDAAuD;QAC9DC,KAAKlD;QACLmD,OAAO;MACT,CAAA;AACAlD,cAAQC,IAAI,8BAAA;IACd,QAAQ;AACND,cAAQC,IAAI,uDAAA;IACd;EACF;AAGA,MAAIN,QAAQwD,aAAa;AACvBnD,YAAQC,IAAI;iCAAoCH,cAAAA;CAAqB;AACrE,QAAI;AACFkD,eAAS,GAAGlD,cAAAA,YAA0B;QAAEmD,KAAKlD;QAAKmD,OAAO;MAAU,CAAA;AACnElD,cAAQC,IAAI,0CAAA;IACd,QAAQ;AACND,cAAQC,IAAI;aAAgBH,cAAAA,mCAAiD;IAC/E;EACF;AAEAE,UAAQC,IAAI,sCAAA;AACZD,UAAQC,IAAG;AAEX,QAAMmD,UAAUrD,QAAQsD,QAAQJ,IAAG;AACnCjD,UAAQC,IAAI,eAAA;AACZ,MAAImD,QAASpD,SAAQC,IAAI,UAAUL,IAAAA,EAAM;AACzC,MAAI,CAACD,QAAQwD,YAAanD,SAAQC,IAAI,OAAOH,cAAAA,UAAwB;AACrEE,UAAQC,IAAI,wBAAA;AACZD,UAAQC,IAAI,cAAA;AACZD,UAAQC,IAAG;AACXD,UAAQC,IAAI,aAAA;AACZD,UAAQC,IAAI,qDAAA;AACZD,UAAQC,IAAI,gDAAA;AACZD,UAAQC,IAAI,2CAAA;AACZD,UAAQC,IAAI,4CAAA;AACZD,UAAQC,IAAG;AACb;AAzRsBP;;;ADPtB,SAAS4D,IAAIC,UAAkBC,cAAqB;AAClD,QAAMC,KAAKC,gBAAgB;IAAEC,OAAOC,QAAQC;IAAOC,QAAQF,QAAQG;EAAO,CAAA;AAC1E,QAAMC,SAASR,eAAe,KAAKA,YAAAA,MAAkB;AACrD,SAAO,IAAIS,QAAQ,CAACC,QAAAA;AAClBT,OAAGF,SAAS,KAAKA,QAAAA,GAAWS,MAAAA,MAAY,CAACG,WAAAA;AACvCV,SAAGW,MAAK;AACRF,UAAIC,OAAOE,KAAI,KAAMb,gBAAgB,EAAA;IACvC,CAAA;EACF,CAAA;AACF;AATSF;AAWT,eAAegB,OAAOf,UAAkBgB,SAAmBC,aAAa,GAAC;AACvEC,UAAQC,IAAI,KAAKnB,QAAAA,EAAU;AAC3B,WAASoB,IAAI,GAAGA,IAAIJ,QAAQK,QAAQD,KAAK;AACvC,UAAME,SAASF,MAAMH,aAAa,MAAM;AACxCC,YAAQC,IAAI,MAAMG,MAAAA,IAAUF,IAAI,CAAA,KAAMJ,QAAQI,CAAAA,CAAE,EAAE;EACpD;AACA,QAAMR,SAAS,MAAMb,IAAI,UAAUwB,OAAON,aAAa,CAAA,CAAA;AACvD,QAAMO,MAAMC,SAASb,QAAQ,EAAA,IAAM;AACnC,SAAOI,QAAQQ,GAAAA,KAAQR,QAAQC,UAAAA;AACjC;AATeF;AAWf,eAAeW,QAAQ1B,UAAkB2B,aAAa,MAAI;AACxD,QAAMC,OAAOD,aAAa,QAAQ;AAClC,QAAMf,SAAS,MAAMb,IAAI,GAAGC,QAAAA,KAAa4B,IAAAA,GAAO;AAChD,MAAI,CAAChB,OAAQ,QAAOe;AACpB,SAAOf,OAAOiB,YAAW,EAAGC,WAAW,GAAA;AACzC;AALeJ;AAOR,SAASK,oBAAoBC,SAAgB;AAClDA,UACGC,QAAQ,YAAA,EACRC,MAAM,MAAA,EACNC,YAAY,6DAAA,EACZC,OAAO,yBAAyB,6CAAA,EAChCA,OAAO,kBAAkB,oCAAA,EACzBA,OAAO,SAAS,2BAAA,EAChBA,OAAO,YAAY,yBAAA,EACnBA,OAAO,aAAa,wCAAA,EACpBA,OAAO,gBAAgB,8BAAA,EACvBA,OAAO,eAAe,yCAAA,EACtBC,OAAO,OAAOC,MAA0BC,SAAAA;AACvCrB,YAAQC,IAAG;AAGX,QAAI,CAACmB,MAAM;AACTA,aAAO,MAAMvC,IAAI,gBAAgB,QAAA;IACnC;AAEA,QAAIyC;AACJ,QAAIF,SAAS,KAAK;AAChBE,kBAAYC,QAAQ,GAAA;AACpBH,aAAOI,SAASF,SAAAA;IAClB,OAAO;AACLA,kBAAYC,QAAQF,KAAKC,aAAaF,IAAAA;IACxC;AAGA,QAAIK,WAAWH,SAAAA,GAAY;AACzB,YAAMI,UAAUC,YAAYL,SAAAA;AAC5B,UAAII,QAAQvB,SAAS,GAAG;AACtB,YAAIkB,KAAKO,OAAO;AACd5B,kBAAQC,IAAI,gCAAgCqB,SAAAA;CAAgB;QAC9D,OAAO;AACLtB,kBAAQC,IAAI,gBAAgBmB,IAAAA,iBAAqB;AACjD,gBAAMS,QAAQH,QAAQI,MAAM,GAAG,CAAA;AAC/B,qBAAWC,SAASF,OAAO;AACzB7B,oBAAQC,IAAI,SAAS8B,KAAAA,EAAO;UAC9B;AACA,cAAIL,QAAQvB,SAAS,GAAG;AACtBH,oBAAQC,IAAI,eAAeyB,QAAQvB,SAAS,CAAA,OAAQ;UACtD;AACAH,kBAAQC,IAAG;AACX,gBAAM+B,cAAc,MAAMxB,QAAQ,0CAA0C,KAAA;AAC5E,cAAI,CAACwB,aAAa;AAChBhC,oBAAQC,IAAI,cAAA;AACZ;UACF;QACF;AAEA,mBAAW8B,SAASL,SAAS;AAC3BO,iBAAOV,QAAQD,WAAWS,KAAAA,GAAQ;YAAEG,WAAW;YAAMN,OAAO;UAAK,CAAA;QACnE;MACF;IACF;AAGA,QAAIO,iBAAiBd,KAAKe;AAC1B,QAAI,CAACD,gBAAgB;AACnBA,uBAAiB,MAAMtC,OAAO,oBAAoB;QAAC;QAAQ;QAAO;SAAS,CAAA;IAC7E;AAGA,QAAIwC;AACJ,QAAIhB,KAAKiB,QAAQC,QAAW;AAC1BF,gBAAU,MAAM7B,QAAQ,8BAA8B,IAAA;IACxD,OAAO;AACL6B,gBAAUhB,KAAKiB;IACjB;AAGA,QAAIE;AACJ,QAAInB,KAAKoB,YAAYF,QAAW;AAC9BC,oBAAc,MAAMhC,QAAQ,yBAAyB,IAAA;IACvD,OAAO;AACLgC,oBAAcnB,KAAKoB;IACrB;AAEA,UAAMC,YAAY;MAChBtB;MACAE;MACAa;MACAE;MACAG;IACF,CAAA;EACF,CAAA;AACJ;AAvFgB3B;;;AGnChB,SAAS8B,WAAAA,gBAAe;;;ACAxB,SAASC,QAAAA,aAAY;;;ACCd,SAASC,aAAaC,MAAY;AACvC,SAAOA,KACJC,QAAQ,gBAAgB,CAACC,GAAGC,MAAOA,IAAIA,EAAEC,YAAW,IAAK,EAAA,EACzDH,QAAQ,QAAQ,CAACE,MAAMA,EAAEC,YAAW,CAAA;AACzC;AAJgBL;AAOT,SAASM,YAAYL,MAAY;AACtC,QAAMM,SAASP,aAAaC,IAAAA;AAC5B,SAAOM,OAAOC,OAAO,CAAA,EAAGC,YAAW,IAAKF,OAAOG,MAAM,CAAA;AACvD;AAHgBJ;AAMT,SAASK,YAAYV,MAAY;AACtC,SAAOA,KACJC,QAAQ,mBAAmB,OAAA,EAC3BA,QAAQ,WAAW,GAAA,EACnBO,YAAW;AAChB;AALgBE;AAWT,SAASC,UAAUX,MAAY;AACpC,MAAIA,KAAKY,SAAS,GAAA,EAAM,QAAOZ;AAC/B,MAAIA,KAAKY,SAAS,GAAA,KAAQZ,KAAKY,SAAS,GAAA,EAAM,QAAOZ,OAAO;AAC5D,MAAIA,KAAKY,SAAS,IAAA,KAASZ,KAAKY,SAAS,IAAA,EAAO,QAAOZ,OAAO;AAC9D,MAAIA,KAAKY,SAAS,GAAA,KAAQ,CAAC,YAAYC,KAAKb,IAAAA,EAAO,QAAOA,KAAKS,MAAM,GAAG,EAAC,IAAK;AAC9E,SAAOT,OAAO;AAChB;AANgBW;AAaT,SAASG,gBAAgBd,MAAY;AAC1C,MAAIA,KAAKY,SAAS,GAAA,EAAM,QAAOZ;AAC/B,MAAIA,KAAKY,SAAS,GAAA,KAAQZ,KAAKY,SAAS,GAAA,EAAM,QAAOZ,OAAO;AAC5D,MAAIA,KAAKY,SAAS,IAAA,KAASZ,KAAKY,SAAS,IAAA,EAAO,QAAOZ,OAAO;AAC9D,MAAIA,KAAKY,SAAS,GAAA,KAAQ,CAAC,aAAaC,KAAKb,IAAAA,EAAO,QAAOA,KAAKS,MAAM,GAAG,EAAC,IAAK;AAC/E,SAAOT,OAAO;AAChB;AANgBc;;;ADnChB,SAASC,YAAAA,WAAUC,aAAAA,kBAAiB;AAkBpC,eAAsBC,eAAeC,SAA8B;AACjE,QAAM,EAAEC,MAAMC,YAAYC,UAAUC,SAASC,OAAO,YAAYC,QAAO,IAAKN;AAC5E,QAAMO,QAAQC,YAAYP,IAAAA;AAC1B,QAAMQ,SAASC,aAAaT,IAAAA;AAC5B,QAAMU,QAAQC,YAAYX,IAAAA;AAC1B,QAAMY,SAASC,UAAUP,KAAAA;AACzB,QAAMQ,eAAeC,gBAAgBP,MAAAA;AACrC,QAAMQ,YAAYC,MAAKhB,YAAYW,MAAAA;AAEnC,QAAMM,QAAkB,CAAA;AAExB,QAAMC,QAAQ,8BAAOC,cAAsBC,YAAAA;AACzC,UAAMC,WAAWL,MAAKD,WAAWI,YAAAA;AACjC,UAAMG,cAAcD,UAAUD,OAAAA;AAC9BH,UAAMM,KAAKF,QAAAA;EACb,GAJc;AAOd,QAAMH,MACJ,YACA;KACCX,MAAAA;;;;;;;;;;;;;WAaMA,OAAOiB,YAAW,CAAA,6CAA+CnB,KAAAA;WACjEF,SAAS,aAAa,WAAWI,MAAAA,eAAqB,UAAUA,MAAAA,YAAkB,0CAA0CJ,SAAS,aAAa,aAAaE,KAAAA,KAAU,WAAWA,KAAAA,EAAO;WAC3LE,MAAAA,qCAA2CF,KAAAA;;;;;;;;eAQvCE,MAAAA;;;;;;;gCAOiBA,OAAOiB,YAAW,CAAA;0BACxBrB,SAAS,aAAa,WAAWI,MAAAA,eAAqB,UAAUA,MAAAA,YAAkB;;;;;;gFAM5BI,MAAAA;;;;;gBAKhEA,MAAAA;4BACYJ,MAAAA;oBACRA,MAAAA;;;;CAInB;AAIC,QAAMW,MACJ,gBAAgBb,KAAAA,kBAChB;KACCE,MAAAA;;;;;;;;;;;;;;;;iBAgBYA,MAAAA,mDAAyDF,KAAAA;cAC5DE,MAAAA,gDAAsDF,KAAAA;eACrDQ,YAAAA,iDAA6DF,MAAAA;iBAC3DJ,MAAAA,mDAAyDF,KAAAA;iBACzDE,MAAAA,mDAAyDF,KAAAA;iBACzDE,MAAAA,6CAAmDF,KAAAA;iBACnDE,MAAAA,6CAAmDF,KAAAA;;;eAGrDE,MAAAA;+BACgBA,MAAAA,mBAAyBA,MAAAA;4BAC5BA,MAAAA,gBAAsBA,MAAAA;6BACrBM,YAAAA,iBAA6BA,YAAAA;+BAC3BN,MAAAA,mBAAyBA,MAAAA;+BACzBA,MAAAA,mBAAyBA,MAAAA;;6BAE3BA,MAAAA;;sCAESA,MAAAA;;;;;;oCAMFM,YAAAA;;;;;;mCAMDN,MAAAA;wCACKA,MAAAA;;;;+BAITA,MAAAA;;sCAEOA,MAAAA;;;;;;uBAMfA,MAAAA;;;;CAItB;AAIC,QAAMW,MACJ,2BAA2Bb,KAAAA,WAC3B;;;YAGQE,MAAAA;uDAC2CA,MAAAA;;;;;;;qBAOlCA,MAAAA;;;;oBAIDA,MAAAA,8BAAoCA,MAAAA;CACvD;AAGC,QAAMW,MACJ,2BAA2Bb,KAAAA,WAC3B;;qBAEiBE,MAAAA;;;;oBAIDA,MAAAA,8BAAoCA,MAAAA;CACvD;AAGC,QAAMW,MACJ,oBAAoBb,KAAAA,oBACpB,oBAAoBE,MAAAA;;;;;;CAMvB;AAIC,QAAMkB,WAAW;IACf;MACEC,MAAM,UAAUrB,KAAAA;MAChBe,SAAS;YACHb,MAAAA;;;;;;;WAODA,OAAOiB,YAAW,CAAA,sBAAwBjB,MAAAA,gDAAsDF,KAAAA;sBACrFE,MAAAA,8BAAoCF,KAAAA;gBAC1CE,MAAAA,+BAAqCF,KAAAA;;;qBAGhCE,MAAAA;;cAEPA,OAAOiB,YAAW,CAAA,wCAA0CjB,MAAAA;;;6BAG7CA,MAAAA,iBAAuBA,MAAAA;;;;;IAKhD;IACA;MACEmB,MAAM,OAAOrB,KAAAA;MACbe,SAAS;WACJb,OAAOiB,YAAW,CAAA,sBAAwBjB,MAAAA,gDAAsDF,KAAAA;gBAC3FE,MAAAA,+BAAqCF,KAAAA;;;kBAGnCE,MAAAA;;cAEJA,OAAOiB,YAAW,CAAA,wCAA0CjB,MAAAA;;;uCAGnCA,MAAAA;;;;;IAKnC;IACA;MACEmB,MAAM,QAAQf,MAAAA;MACdS,SAAS;WACJb,OAAOiB,YAAW,CAAA,sBAAwBjB,MAAAA,gDAAsDF,KAAAA;gBAC3FE,MAAAA,+BAAqCF,KAAAA;;;mBAGlCQ,YAAAA;;cAELN,OAAOiB,YAAW,CAAA,wCAA0CjB,MAAAA;;;6BAG7CA,MAAAA;;;;;IAKzB;IACA;MACEmB,MAAM,UAAUrB,KAAAA;MAChBe,SAAS;WACJb,OAAOiB,YAAW,CAAA,sBAAwBjB,MAAAA,gDAAsDF,KAAAA;sBACrFE,MAAAA,8BAAoCF,KAAAA;gBAC1CE,MAAAA,+BAAqCF,KAAAA;;;qBAGhCE,MAAAA;;cAEPA,OAAOiB,YAAW,CAAA,wCAA0CjB,MAAAA;;;yCAGjCA,MAAAA,iBAAuBA,MAAAA;;;;;IAK5D;IACA;MACEmB,MAAM,UAAUrB,KAAAA;MAChBe,SAAS;WACJb,OAAOiB,YAAW,CAAA,sBAAwBjB,MAAAA,gDAAsDF,KAAAA;;;qBAGtFE,MAAAA;;cAEPA,OAAOiB,YAAW,CAAA,wCAA0CjB,MAAAA;;;;;;;;IAQtE;;AAGF,aAAWoB,MAAMF,UAAU;AACzB,UAAMP,MAAM,yBAAyBS,GAAGD,IAAI,IAAIC,GAAGP,OAAO;EAC5D;AAGA,QAAMF,MACJ,uBAAuBb,KAAAA,kBACvB;KACCE,MAAAA;;;;;;;;;gBASWA,MAAAA,8CAAoDF,KAAAA;sBAC9CE,MAAAA,6CAAmDF,KAAAA;sBACnDE,MAAAA,6CAAmDF,KAAAA;;oBAErDE,MAAAA;kCACcA,MAAAA;uBACXA,MAAAA;sBACDA,MAAAA,iBAAuBA,MAAAA;kCACXA,MAAAA,iBAAuBA,MAAAA;;;;eAI1CA,OAAOiB,YAAW,CAAA,0BAA4BjB,MAAAA;CAC5D;AAIC,QAAMW,MACJ,mBAAmBb,KAAAA,sBACnB;KACCE,MAAAA;;;;;;;WAOMA,OAAOiB,YAAW,CAAA,sBAAwBjB,MAAAA,sCAA4CF,KAAAA;;;eAGlFE,MAAAA;;cAEDA,OAAOiB,YAAW,CAAA,wCAA0CjB,MAAAA;;;;;;sCAMpCA,MAAAA;;;;CAIrC;AAIC,MAAIJ,SAAS,YAAY;AACvB,UAAMe,MACJ,yCAAyCb,KAAAA,kBACzC;eACSE,MAAAA;;;;;;;;;;iBAUEA,MAAAA,gDAAsDF,KAAAA;gBACvDE,MAAAA,8CAAoDF,KAAAA;sBAC9CE,MAAAA,6CAAmDF,KAAAA;sBACnDE,MAAAA,6CAAmDF,KAAAA;;;uBAGlDE,MAAAA,0BAAgCA,MAAAA;oCACnBA,MAAAA;;wCAEIA,MAAAA;;;;6BAIXA,MAAAA;;;;4BAIDA,MAAAA,iBAAuBA,MAAAA;;oBAE/BA,MAAAA;;;;;;;;;;wCAUoBA,MAAAA,iBAAuBA,MAAAA;;mDAEZA,MAAAA;;;;;;;6DAOUA,MAAAA;;;;CAI5D;EAEC;AAGA,MAAI,CAACN,YAAY,CAACG,SAAS;AACzB,UAAMc,MACJ,mBAAmBb,KAAAA,cACnB;KACDE,MAAAA;;;;;;;;;;;;WAYMA,MAAAA,+BAAqCF,KAAAA;;YAEpCE,MAAAA;QACJA,MAAAA;;;;;;eAMOA,MAAAA;uCACwBA,MAAAA;;6CAEMA,MAAAA;;iBAE5BA,MAAAA;YACLA,MAAAA;;;;;;;+BAOmBA,MAAAA,WAAiBA,MAAAA;iBAC/BA,MAAAA;;;cAGHA,MAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8Bb;AAGG,UAAMW,MACJ,wBAAwBb,KAAAA,aACxB;KACDE,MAAAA;;;;;OAKEA,MAAAA;OACAA,MAAAA;;;;;eAKQA,MAAAA;;;qBAGMA,MAAAA;iBACJA,MAAAA;;;6BAGYA,MAAAA;;yBAEJA,MAAAA;;iBAERA,MAAAA;;;;;;;kBAOCA,MAAAA;;;;CAIjB;EAEC;AAGA,QAAMqB,mBAAmB5B,YAAYO,QAAQI,MAAAA;AAE7C,SAAOM;AACT;AAphBsBpB;AAuhBtB,eAAe+B,mBACb5B,YACAO,QACAI,QAAc;AAEd,QAAMkB,YAAYb,MAAKhB,YAAY,UAAA;AACnC,QAAM8B,SAAS,MAAMC,WAAWF,SAAAA;AAEhC,MAAI,CAACC,QAAQ;AACX,UAAMR,cACJO,WACA;WACKtB,MAAAA,oBAA0BI,MAAAA;;4CAEOJ,MAAAA;CAC3C;AAEG;EACF;AAEA,MAAIa,UAAU,MAAMY,UAASH,WAAW,OAAA;AAGxC,QAAMI,aAAa,YAAY1B,MAAAA,oBAA0BI,MAAAA;AACzD,MAAI,CAACS,QAAQc,SAAS,GAAG3B,MAAAA,QAAc,GAAG;AAExC,UAAM4B,gBAAgBf,QAAQgB,YAAY,SAAA;AAC1C,QAAID,kBAAkB,IAAI;AACxB,YAAME,UAAUjB,QAAQkB,QAAQ,MAAMH,aAAAA;AACtCf,gBAAUA,QAAQmB,MAAM,GAAGF,UAAU,CAAA,IAAKJ,aAAa,OAAOb,QAAQmB,MAAMF,UAAU,CAAA;IACxF,OAAO;AACLjB,gBAAUa,aAAa,OAAOb;IAChC;AAIAA,cAAUA,QAAQoB,QAAQ,yBAAyB,CAACC,QAAQC,MAAMC,UAAUC,UAAAA;AAC1E,YAAMC,UAAUF,SAASG,KAAI;AAC7B,UAAI,CAACD,SAAS;AAEZ,eAAO,GAAGH,IAAAA,GAAOnC,MAAAA,SAAeqC,KAAAA;MAClC;AAEA,YAAMG,aAAaF,QAAQG,SAAS,GAAA,IAAO,KAAK;AAChD,aAAO,GAAGN,IAAAA,GAAOC,SAASM,QAAO,CAAA,GAAKF,UAAAA,IAAcxC,MAAAA,SAAeqC,KAAAA;IACrE,CAAA;EACF;AAEA,QAAMM,WAAUrB,WAAWT,SAAS,OAAA;AACtC;AAjDeQ;;;AE5iBf,SAASuB,QAAAA,aAAY;AASrB,eAAsBC,gBAAgBC,SAA+B;AACnE,QAAM,EAAEC,MAAMC,OAAM,IAAKF;AACzB,QAAMG,QAAQC,YAAYH,IAAAA;AAC1B,QAAMI,SAASC,aAAaL,IAAAA;AAC5B,QAAMM,QAAkB,CAAA;AAExB,QAAMC,WAAWC,MAAKP,QAAQ,GAAGC,KAAAA,aAAkB;AACnD,QAAMO,cACJF,UACA;;;mBAGeH,MAAAA;;;;;KAKdA,MAAAA;;;;;;;wBAOmBA,MAAAA;;;eAGTA,MAAAA;YACHA,MAAAA;;iCAEqBA,MAAAA;;;;;;;;;;;;;gCAaDA,MAAAA;;;;;;;;;;;;;;;;;;;;mBAoBbF,KAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgClB;AAECI,QAAMI,KAAKH,QAAAA;AAEX,SAAOD;AACT;AApGsBR;;;ACTtB,SAASa,QAAAA,aAAY;AASrB,eAAsBC,mBAAmBC,SAAkC;AACzE,QAAM,EAAEC,MAAMC,OAAM,IAAKF;AACzB,QAAMG,QAAQC,YAAYH,IAAAA;AAC1B,QAAMI,QAAQC,YAAYL,IAAAA;AAC1B,QAAMM,QAAkB,CAAA;AAExB,QAAMC,WAAWC,MAAKP,QAAQ,GAAGC,KAAAA,gBAAqB;AACtD,QAAMO,cACJF,UACA;;mBAEeG,aAAaV,IAAAA,CAAAA;;;;;KAK3BU,aAAaV,IAAAA,CAAAA;;;oBAGEI,KAAAA;;;yCAGqBA,KAAAA;;;mBAGtBA,KAAAA;;kBAEDA,KAAAA,aAAkBM,aAAaV,IAAAA,CAAAA;;;;;;CAMhD;AAECM,QAAMK,KAAKJ,QAAAA;AAEX,SAAOD;AACT;AAtCsBR;;;ACTtB,SAASc,QAAAA,aAAY;AASrB,eAAsBC,cAAcC,SAA6B;AAC/D,QAAM,EAAEC,MAAMC,OAAM,IAAKF;AACzB,QAAMG,QAAQC,YAAYH,IAAAA;AAC1B,QAAMI,QAAQC,YAAYL,IAAAA;AAC1B,QAAMM,SAASC,aAAaP,IAAAA;AAC5B,QAAMQ,QAAkB,CAAA;AAExB,QAAMC,WAAWC,MAAKT,QAAQ,GAAGC,KAAAA,WAAgB;AACjD,QAAMS,cACJF,UACA;;;;KAICH,MAAAA;;;;;;mBAMcF,KAAAA;;;;wBAIKA,KAAAA;;;;;;;;;;;;;;;;;;;;;;CAsBvB;AAECI,QAAMI,KAAKH,QAAAA;AAEX,SAAOD;AACT;AAnDsBV;;;ACTtB,SAASe,QAAAA,aAAY;AASrB,eAAsBC,gBAAgBC,SAA+B;AACnE,QAAM,EAAEC,MAAMC,OAAM,IAAKF;AACzB,QAAMG,QAAQC,YAAYH,IAAAA;AAC1B,QAAMI,SAASC,aAAaL,IAAAA;AAC5B,QAAMM,QAAkB,CAAA;AAExB,QAAMC,WAAWC,MAAKP,QAAQ,GAAGC,KAAAA,aAAkB;AACnD,QAAMO,cACJF,UACA;;;eAGWH,MAAAA;;;;;;CAMd;AAECE,QAAMI,KAAKH,QAAAA;AAEX,SAAOD;AACT;AAvBsBR;;;ACTtB,SAASa,QAAAA,aAAY;AASrB,eAAsBC,mBAAmBC,SAAkC;AACzE,QAAM,EAAEC,MAAMC,OAAM,IAAKF;AACzB,QAAMG,QAAQC,YAAYH,IAAAA;AAC1B,QAAMI,SAASC,aAAaL,IAAAA;AAC5B,QAAMM,QAAkB,CAAA;AAExB,QAAMC,WAAWC,MAAKP,QAAQ,GAAGC,KAAAA,gBAAqB;AACtD,QAAMO,cACJF,UACA;;;;eAIWH,MAAAA;;;;;2BAKYA,MAAAA;;;;;8BAKGA,MAAAA;;;CAG7B;AAECE,QAAMI,KAAKH,QAAAA;AAEX,SAAOD;AACT;AA/BsBR;;;ACTtB,SAASa,QAAAA,aAAY;AASrB,eAAsBC,YAAYC,SAA2B;AAC3D,QAAM,EAAEC,MAAMC,OAAM,IAAKF;AACzB,QAAMG,QAAQC,YAAYH,IAAAA;AAC1B,QAAMI,SAASC,aAAaL,IAAAA;AAC5B,QAAMM,QAAQC,YAAYP,IAAAA;AAC1B,QAAMQ,QAAkB,CAAA;AAExB,QAAMC,WAAWC,MAAKT,QAAQ,GAAGC,KAAAA,SAAc;AAC/C,QAAMS,cACJF,UACA;;eAEWH,KAAAA;;;;;cAKDF,MAAAA,wBAA8BE,KAAAA;CAC3C;AAECE,QAAMI,KAAKH,QAAAA;AAEX,SAAOD;AACT;AAvBsBV;;;ACTtB,SAASe,QAAAA,aAAY;AACrB,SAASC,cAAAA,mBAAkB;AAC3B,SAASC,mBAAAA,wBAAuB;AAUhC,eAAeC,SAAQC,SAAe;AACpC,QAAMC,KAAKC,iBAAgB;IAAEC,OAAOC,QAAQC;IAAOC,QAAQF,QAAQG;EAAO,CAAA;AAC1E,SAAO,IAAIC,QAAQ,CAACC,aAAAA;AAClBR,OAAGS,SAAS,KAAKV,OAAAA,WAAkB,CAACW,WAAAA;AAClCV,SAAGW,MAAK;AACRH,MAAAA,SAAQE,OAAOE,KAAI,EAAGC,YAAW,MAAO,GAAA;IAC1C,CAAA;EACF,CAAA;AACF;AARef,OAAAA,UAAAA;AAUf,eAAsBgB,eAAeC,SAA8B;AACjE,QAAMC,WAAWC,MAAKF,QAAQG,QAAQ,gBAAA;AACtC,QAAMC,aAAaJ,QAAQI,cAAc;AACzC,QAAMC,cAAcL,QAAQK,eAAe;AAE3C,MAAIC,YAAWL,QAAAA,KAAa,CAACD,QAAQO,OAAO;AAC1C,UAAMC,YAAY,MAAMzB,SAAQ,2CAAA;AAChC,QAAI,CAACyB,WAAW;AACdC,cAAQC,IAAI,uDAAA;AACZ,aAAO,CAAA;IACT;EACF;AAEA,QAAMC,cACJV,UACA;;;iBAGaG,UAAAA;kBACCC,WAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BjB;AAGC,SAAO;IAACJ;;AACV;AAjDsBF;;;ATXtB,SAASa,eAAeC,OAAe;AACrC,QAAMC,MAAMC,QAAQD,IAAG;AACvBE,UAAQC,IAAI;cAAiBJ,MAAMK,MAAM,QAAQL,MAAMK,WAAW,IAAI,KAAK,GAAA,GAAM;AACjF,aAAWC,KAAKN,OAAO;AACrBG,YAAQC,IAAI,OAAOE,EAAEC,QAAQN,MAAM,KAAK,EAAA,CAAA,EAAK;EAC/C;AACAE,UAAQC,IAAG;AACb;AAPSL;AASF,SAASS,wBAAwBC,SAAgB;AACtD,QAAMC,MAAMD,QAAQE,QAAQ,UAAA,EAAYC,MAAM,GAAA,EAAKC,YAAY,yBAAA;AAG/DH,MACGC,QAAQ,eAAA,EACRE,YAAY,4CAAA,EACZC,OAAO,eAAe,yCAAA,EACtBA,OAAO,cAAc,2BAAA,EACrBA,OAAO,iBAAiB,iDAAiD,UAAA,EACzEA,OAAO,aAAa,uCAAA,EACpBA,OAAO,uBAAuB,qBAAqB,aAAA,EACnDC,OAAO,OAAOC,MAAcC,SAAAA;AAC3B,UAAMjB,QAAQ,MAAMkB,eAAe;MACjCF;MACAG,YAAYC,SAAQH,KAAKE,UAAU;MACnCE,UAAUJ,KAAKK,WAAW;MAC1BC,SAASN,KAAKO,UAAU;MACxBC,MAAMR,KAAKQ;MACXC,SAAST,KAAKS;IAChB,CAAA;AACA3B,mBAAeC,KAAAA;EACjB,CAAA;AAGFU,MACGC,QAAQ,gBAAA,EACRE,YAAY,oEAAA,EACZC,OAAO,mBAAmB,oBAAoB,cAAA,EAC9CC,OAAO,OAAOC,MAAcC,SAAAA;AAC3B,UAAMjB,QAAQ,MAAM2B,gBAAgB;MAAEX;MAAMY,QAAQR,SAAQH,KAAKY,GAAG;IAAE,CAAA;AACtE9B,mBAAeC,KAAAA;EACjB,CAAA;AAGFU,MACGC,QAAQ,mBAAA,EACRE,YAAY,yCAAA,EACZC,OAAO,mBAAmB,oBAAoB,gBAAA,EAC9CC,OAAO,OAAOC,MAAcC,SAAAA;AAC3B,UAAMjB,QAAQ,MAAM8B,mBAAmB;MAAEd;MAAMY,QAAQR,SAAQH,KAAKY,GAAG;IAAE,CAAA;AACzE9B,mBAAeC,KAAAA;EACjB,CAAA;AAGFU,MACGC,QAAQ,cAAA,EACRE,YAAY,4CAAA,EACZC,OAAO,mBAAmB,oBAAoB,YAAA,EAC9CC,OAAO,OAAOC,MAAcC,SAAAA;AAC3B,UAAMjB,QAAQ,MAAM+B,cAAc;MAAEf;MAAMY,QAAQR,SAAQH,KAAKY,GAAG;IAAE,CAAA;AACpE9B,mBAAeC,KAAAA;EACjB,CAAA;AAGFU,MACGC,QAAQ,gBAAA,EACRE,YAAY,6BAAA,EACZC,OAAO,mBAAmB,oBAAoB,cAAA,EAC9CC,OAAO,OAAOC,MAAcC,SAAAA;AAC3B,UAAMjB,QAAQ,MAAMgC,gBAAgB;MAAEhB;MAAMY,QAAQR,SAAQH,KAAKY,GAAG;IAAE,CAAA;AACtE9B,mBAAeC,KAAAA;EACjB,CAAA;AAGFU,MACGC,QAAQ,mBAAA,EACRE,YAAY,kDAAA,EACZC,OAAO,mBAAmB,oBAAoB,iBAAA,EAC9CC,OAAO,OAAOC,MAAcC,SAAAA;AAC3B,UAAMjB,QAAQ,MAAMiC,mBAAmB;MAAEjB;MAAMY,QAAQR,SAAQH,KAAKY,GAAG;IAAE,CAAA;AACzE9B,mBAAeC,KAAAA;EACjB,CAAA;AAGFU,MACGC,QAAQ,YAAA,EACRE,YAAY,2BAAA,EACZC,OAAO,mBAAmB,oBAAoB,UAAA,EAC9CC,OAAO,OAAOC,MAAcC,SAAAA;AAC3B,UAAMjB,QAAQ,MAAMkC,YAAY;MAAElB;MAAMY,QAAQR,SAAQH,KAAKY,GAAG;IAAE,CAAA;AAClE9B,mBAAeC,KAAAA;EACjB,CAAA;AAGFU,MACGC,QAAQ,QAAA,EACRE,YAAY,+CAAA,EACZC,OAAO,uBAAuB,0BAA0B,aAAA,EACxDA,OAAO,iBAAiB,+CAA+C,UAAA,EACvEA,OAAO,eAAe,qDAAA,EACtBC,OAAO,OAAOE,SAAAA;AACb,UAAMjB,QAAQ,MAAMmC,eAAe;MACjCP,QAAQR,SAAQ,GAAA;MAChBD,YAAYF,KAAKE;MACjBiB,aAAanB,KAAKQ;MAClBY,OAAOpB,KAAKoB;IACd,CAAA;AACAtC,mBAAeC,KAAAA;EACjB,CAAA;AACJ;AApGgBQ;;;AUpBhB,SAAS8B,YAAAA,iBAAgB;AAGlB,SAASC,gBAAgBC,SAAiBC,KAAY;AAC3DC,EAAAA,UAASF,SAAS;IAChBC;IACAE,OAAO;EACT,CAAA;AACF;AALgBJ;;;ACAT,SAASK,oBAAoBC,SAAgB;AAClDA,UACGC,QAAQ,KAAA,EACRC,YAAY,+DAAA,EACZC,OAAO,sBAAsB,cAAc,cAAA,EAC3CA,OAAO,qBAAqB,aAAA,EAC5BC,OAAO,CAACC,SAAAA;AACP,UAAMC,UAAoB,CAAA;AAC1B,QAAID,KAAKE,KAAMD,SAAQE,KAAK,QAAQH,KAAKE,IAAI,EAAE;AAK/C,UAAME,MAAM,yBAAyBJ,KAAKK,KAAK;AAC/C,UAAMC,UAAUL,QAAQM,SAAS,GAAGN,QAAQO,KAAK,GAAA,CAAA,IAAQJ,GAAAA,KAAQA;AAEjEK,YAAQC,IAAI;gCAAmC;AAC/CD,YAAQC,IAAI,aAAaV,KAAKK,KAAK,EAAE;AACrCI,YAAQC,IAAI;CAAiC;AAE7C,QAAI;AACFC,sBAAgBL,OAAAA;IAClB,QAAQ;IAER;EACF,CAAA;AAEFX,UACGC,QAAQ,OAAA,EACRC,YAAY,+BAAA,EACZE,OAAO,MAAA;AACNU,YAAQC,IAAI,kCAAA;AACZC,oBAAgB,gBAAA;EAClB,CAAA;AAEFhB,UACGC,QAAQ,OAAA,EACRC,YAAY,yBAAA,EACZC,OAAO,sBAAsB,cAAc,eAAA,EAC3CA,OAAO,qBAAqB,aAAA,EAC5BC,OAAO,CAACC,SAAAA;AACP,UAAMC,UAAoB;MAAC;;AAC3B,QAAID,KAAKE,KAAMD,SAAQE,KAAK,QAAQH,KAAKE,IAAI,EAAE;AAC/CS,oBAAgB,GAAGV,QAAQO,KAAK,GAAA,CAAA,SAAaR,KAAKK,KAAK,EAAE;EAC3D,CAAA;AAEFV,UACGC,QAAQ,WAAA,EACRC,YAAY,yCAAA,EACZC,OAAO,sBAAsB,cAAc,cAAA,EAC3CA,OAAO,qBAAqB,aAAA,EAC5BC,OAAO,CAACC,SAAAA;AACP,UAAMC,UAAUD,KAAKE,OAAO,QAAQF,KAAKE,IAAI,MAAM;AACnD,QAAI;AACFS,sBAAgB,GAAGV,OAAAA,mCAA0CD,KAAKK,KAAK,EAAE;IAC3E,QAAQ;IAER;EACF,CAAA;AACJ;AA3DgBX;;;ACHhB,SAASkB,UAAUC,SAASC,YAAY;AAGjC,SAASC,oBAAoBC,SAAgB;AAClDA,UACGC,QAAQ,MAAA,EACRC,YAAY,iCAAA,EACZC,OAAO,MAAA;AACNC,YAAQC,IAAI;;;;gBAIFC,SAAAA,CAAAA,IAAcC,QAAAA,CAAAA,KAAcC,KAAAA,CAAAA;gBAC5BC,QAAQC,OAAO;;;;;;;CAO9B;EACG,CAAA;AACJ;AAnBgBX;;;ACqDT,SAASY,uBAAuBC,SAAkBC,QAAyB;AAChF,MAAI,CAACA,QAAQC,UAAUC,OAAQ;AAE/B,aAAWC,OAAOH,OAAOC,UAAU;AACjCG,0BAAsBL,SAASI,GAAAA;EACjC;AACF;AANgBL;AAQhB,SAASM,sBAAsBL,SAAkBM,KAA0B;AACzE,QAAMC,UAAUP,QAAQO,QAAQD,IAAIE,IAAI,EAAEC,YAAYH,IAAIG,WAAW;AAErE,MAAIH,IAAII,SAAS;AACf,eAAWC,SAASL,IAAII,SAAS;AAC/BH,cAAQI,MAAMA,KAAAA;IAChB;EACF;AAGAJ,UAAQK,mBAAmB,IAAA;AAC3BL,UAAQM,SAAS,aAAa,4CAAA;AAE9BN,UAAQO,OAAO,CAACC,SAAAA;AACd,UAAMC,YAAYD,KAAKE,KAAK,GAAA;AAC5B,UAAMC,QAAQC,MAAMC,QAAQd,IAAIY,KAAK,IAAIZ,IAAIY,QAAQ;MAACZ,IAAIY;;AAE1D,eAAWG,QAAQH,OAAO;AAExB,YAAMI,WAAWN,YAAY,GAAGK,IAAAA,IAAQL,SAAAA,KAAcK;AACtDE,cAAQC,IAAI,OAAOF,QAAAA,EAAU;AAC7B,UAAI;AACFG,wBAAgBH,QAAAA;MAClB,SAASI,KAAU;AACjBH,gBAAQI,MAAM,qBAAqBrB,IAAIE,IAAI,EAAE;AAC7CoB,gBAAQC,WAAW;AACnB;MACF;IACF;EACF,CAAA;AACF;AA9BSxB;;;AChET,SAASyB,YAAAA,WAAUC,UAAAA,eAAc;AACjC,SAASC,QAAAA,cAAY;AA6CrB,IAAMC,eAAe;EAAC;EAAkB;EAAkB;EAAmB;;AAG7E,eAAsBC,eAAeC,KAAW;AAC9C,aAAWC,YAAYH,cAAc;AACnC,UAAMI,WAAWC,OAAKH,KAAKC,QAAAA;AAC3B,QAAI;AACF,YAAMG,QAAOF,QAAAA;IACf,QAAQ;AACN;IACF;AAEA,QAAID,SAASI,SAAS,OAAA,GAAU;AAC9B,YAAMC,UAAU,MAAMC,UAASL,UAAU,OAAA;AACzC,aAAOM,KAAKC,MAAMH,OAAAA;IACpB;AAGA,QAAI;AACF,YAAM,EAAEI,cAAa,IAAK,MAAM,OAAO,KAAA;AACvC,YAAMC,MAAM,MAAM,OAAOD,cAAcR,QAAAA,EAAUU;AACjD,aAAOD,IAAIE,WAAWF;IACxB,SAASG,KAAK;AACZ,UAAIb,SAASI,SAAS,KAAA,GAAQ;AAC5BU,gBAAQC,KACN,2BAA2Bf,QAAAA,4GACzB;MAEN;AACA;IACF;EACF;AACA,SAAO;AACT;AA9BsBF;;;AlBzCtB,eAAekB,OAAAA;AACb,QAAMC,UAAU,IAAIC,QAAAA;AAEpBD,UACGE,KAAK,MAAA,EACLC,YAAY,sEAAA,EACZC,QAAQ,OAAA;AAGX,QAAMC,SAAS,MAAMC,eAAeC,QAAQC,IAAG,CAAA;AAE/CC,sBAAoBT,OAAAA;AACpBU,0BAAwBV,OAAAA;AACxBW,sBAAoBX,OAAAA;AACpBY,sBAAoBZ,OAAAA;AACpBa,yBAAuBb,SAASK,MAAAA;AAEhCL,UAAQc,mBAAkB;AAE1B,QAAMd,QAAQe,WAAWR,QAAQS,IAAI;AACvC;AApBejB;AAsBfA,KAAAA,EAAOkB,MAAM,CAACC,QAAAA;AACZC,UAAQC,MAAMF,eAAeG,QAAQH,IAAII,UAAUJ,GAAAA;AACnDX,UAAQgB,WAAW;AACrB,CAAA;","names":["Command","resolve","basename","createInterface","existsSync","readdirSync","rmSync","join","execSync","writeFile","mkdir","access","readFile","dirname","writeFileSafe","filePath","content","mkdir","dirname","recursive","writeFile","fileExists","filePath","access","initProject","options","name","directory","packageManager","dir","console","log","writeFileSafe","join","JSON","stringify","version","type","scripts","dev","build","start","test","typecheck","lint","format","dependencies","express","zod","pino","devDependencies","vite","vitest","typescript","prettier","compilerOptions","target","module","moduleResolution","lib","types","strict","esModuleInterop","skipLibCheck","sourceMap","declaration","experimentalDecorators","emitDecoratorMetadata","outDir","rootDir","paths","include","semi","singleQuote","trailingComma","printWidth","tabWidth","initGit","execSync","cwd","stdio","installDeps","needsCd","process","ask","question","defaultValue","rl","createInterface","input","process","stdin","output","stdout","suffix","Promise","res","answer","close","trim","choose","options","defaultIdx","console","log","i","length","marker","String","idx","parseInt","confirm","defaultYes","hint","toLowerCase","startsWith","registerInitCommand","program","command","alias","description","option","action","name","opts","directory","resolve","basename","existsSync","entries","readdirSync","force","shown","slice","entry","shouldClear","rmSync","recursive","packageManager","pm","initGit","git","undefined","installDeps","install","initProject","resolve","join","toPascalCase","name","replace","_","c","toUpperCase","toCamelCase","pascal","charAt","toLowerCase","slice","toKebabCase","pluralize","endsWith","test","pluralizePascal","readFile","writeFile","generateModule","options","name","modulesDir","noEntity","noTests","repo","minimal","kebab","toKebabCase","pascal","toPascalCase","camel","toCamelCase","plural","pluralize","pluralPascal","pluralizePascal","moduleDir","join","files","write","relativePath","content","fullPath","writeFileSafe","push","toUpperCase","useCases","file","uc","autoRegisterModule","indexPath","exists","fileExists","readFile","importLine","includes","lastImportIdx","lastIndexOf","lineEnd","indexOf","slice","replace","_match","open","existing","close","trimmed","trim","needsComma","endsWith","trimEnd","writeFile","join","generateAdapter","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateMiddleware","options","name","outDir","kebab","toKebabCase","camel","toCamelCase","files","filePath","join","writeFileSafe","toPascalCase","push","join","generateGuard","options","name","outDir","kebab","toKebabCase","camel","toCamelCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateService","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateController","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateDto","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","camel","toCamelCase","files","filePath","join","writeFileSafe","push","join","existsSync","createInterface","confirm","message","rl","createInterface","input","process","stdin","output","stdout","Promise","resolve","question","answer","close","trim","toLowerCase","generateConfig","options","filePath","join","outDir","modulesDir","defaultRepo","existsSync","force","overwrite","console","log","writeFileSafe","printGenerated","files","cwd","process","console","log","length","f","replace","registerGenerateCommand","program","gen","command","alias","description","option","action","name","opts","generateModule","modulesDir","resolve","noEntity","entity","noTests","tests","repo","minimal","generateAdapter","outDir","out","generateMiddleware","generateGuard","generateService","generateController","generateDto","generateConfig","defaultRepo","force","execSync","runShellCommand","command","cwd","execSync","stdio","registerRunCommands","program","command","description","option","action","opts","envVars","port","push","cmd","entry","fullCmd","length","join","console","log","runShellCommand","platform","release","arch","registerInfoCommand","program","command","description","action","console","log","platform","release","arch","process","version","registerCustomCommands","program","config","commands","length","cmd","registerSingleCommand","def","command","name","description","aliases","alias","allowUnknownOption","argument","action","args","extraArgs","join","steps","Array","isArray","step","finalCmd","console","log","runShellCommand","err","error","process","exitCode","readFile","access","join","CONFIG_FILES","loadKickConfig","cwd","filename","filepath","join","access","endsWith","content","readFile","JSON","parse","pathToFileURL","mod","href","default","err","console","warn","main","program","Command","name","description","version","config","loadKickConfig","process","cwd","registerInitCommand","registerGenerateCommand","registerRunCommands","registerInfoCommand","registerCustomCommands","showHelpAfterError","parseAsync","argv","catch","err","console","error","Error","message","exitCode"]}
package/dist/index.d.ts CHANGED
@@ -55,6 +55,8 @@ interface InitProjectOptions {
55
55
  name: string;
56
56
  directory: string;
57
57
  packageManager?: 'pnpm' | 'npm' | 'yarn';
58
+ initGit?: boolean;
59
+ installDeps?: boolean;
58
60
  }
59
61
  /** Scaffold a new KickJS project */
60
62
  declare function initProject(options: InitProjectOptions): Promise<void>;
package/dist/index.js CHANGED
@@ -838,6 +838,7 @@ __name(generateDto, "generateDto");
838
838
 
839
839
  // src/generators/project.ts
840
840
  import { join as join8 } from "path";
841
+ import { execSync } from "child_process";
841
842
  async function initProject(options) {
842
843
  const { name, directory, packageManager = "pnpm" } = options;
843
844
  const dir = directory;
@@ -977,6 +978,37 @@ bootstrap({
977
978
  await writeFileSafe(join8(dir, "src/modules/index.ts"), `import type { AppModuleClass } from '@forinda/kickjs-core'
978
979
 
979
980
  export const modules: AppModuleClass[] = []
981
+ `);
982
+ await writeFileSafe(join8(dir, "kick.config.ts"), `import { defineConfig } from '@forinda/kickjs-cli'
983
+
984
+ export default defineConfig({
985
+ modulesDir: 'src/modules',
986
+ defaultRepo: 'inmemory',
987
+
988
+ commands: [
989
+ {
990
+ name: 'test',
991
+ description: 'Run tests with Vitest',
992
+ steps: 'npx vitest run',
993
+ },
994
+ {
995
+ name: 'format',
996
+ description: 'Format code with Prettier',
997
+ steps: 'npx prettier --write src/',
998
+ },
999
+ {
1000
+ name: 'format:check',
1001
+ description: 'Check formatting without writing',
1002
+ steps: 'npx prettier --check src/',
1003
+ },
1004
+ {
1005
+ name: 'check',
1006
+ description: 'Run typecheck + format check',
1007
+ steps: ['npx tsc --noEmit', 'npx prettier --check src/'],
1008
+ aliases: ['verify', 'ci'],
1009
+ },
1010
+ ],
1011
+ })
980
1012
  `);
981
1013
  await writeFileSafe(join8(dir, "vitest.config.ts"), `import { defineConfig } from 'vitest/config'
982
1014
  import swc from 'unplugin-swc'
@@ -990,13 +1022,48 @@ export default defineConfig({
990
1022
  },
991
1023
  })
992
1024
  `);
993
- console.log(" Project scaffolded successfully!");
1025
+ if (options.initGit) {
1026
+ try {
1027
+ execSync("git init", {
1028
+ cwd: dir,
1029
+ stdio: "pipe"
1030
+ });
1031
+ execSync("git add -A", {
1032
+ cwd: dir,
1033
+ stdio: "pipe"
1034
+ });
1035
+ execSync('git commit -m "chore: initial commit from kick new"', {
1036
+ cwd: dir,
1037
+ stdio: "pipe"
1038
+ });
1039
+ console.log(" Git repository initialized");
1040
+ } catch {
1041
+ console.log(" Warning: git init failed (git may not be installed)");
1042
+ }
1043
+ }
1044
+ if (options.installDeps) {
1045
+ console.log(`
1046
+ Installing dependencies with ${packageManager}...
1047
+ `);
1048
+ try {
1049
+ execSync(`${packageManager} install`, {
1050
+ cwd: dir,
1051
+ stdio: "inherit"
1052
+ });
1053
+ console.log("\n Dependencies installed successfully!");
1054
+ } catch {
1055
+ console.log(`
1056
+ Warning: ${packageManager} install failed. Run it manually.`);
1057
+ }
1058
+ }
1059
+ console.log("\n Project scaffolded successfully!");
994
1060
  console.log();
1061
+ const needsCd = dir !== process.cwd();
995
1062
  console.log(" Next steps:");
996
- console.log(` cd ${name}`);
997
- console.log(` ${packageManager} install`);
998
- console.log(` kick g module user`);
999
- console.log(` kick dev`);
1063
+ if (needsCd) console.log(` cd ${name}`);
1064
+ if (!options.installDeps) console.log(` ${packageManager} install`);
1065
+ console.log(" kick g module user");
1066
+ console.log(" kick dev");
1000
1067
  console.log();
1001
1068
  console.log(" Commands:");
1002
1069
  console.log(" kick dev Start dev server with Vite HMR");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/generators/module.ts","../src/utils/fs.ts","../src/utils/naming.ts","../src/generators/adapter.ts","../src/generators/middleware.ts","../src/generators/guard.ts","../src/generators/service.ts","../src/generators/controller.ts","../src/generators/dto.ts","../src/generators/project.ts","../src/config.ts"],"sourcesContent":["import { join } from 'node:path'\nimport { writeFileSafe, fileExists } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase, pluralize, pluralizePascal } from '../utils/naming'\nimport { readFile, writeFile } from 'node:fs/promises'\n\ninterface GenerateModuleOptions {\n name: string\n modulesDir: string\n noEntity?: boolean\n noTests?: boolean\n repo?: 'drizzle' | 'inmemory'\n minimal?: boolean\n}\n\n/**\n * Generate a full DDD module with all layers:\n * presentation/ — controller\n * application/ — use-cases, DTOs\n * domain/ — entity, value objects, repository interface, domain service\n * infrastructure/ — repository implementation\n */\nexport async function generateModule(options: GenerateModuleOptions): Promise<string[]> {\n const { name, modulesDir, noEntity, noTests, repo = 'inmemory', minimal } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const camel = toCamelCase(name)\n const plural = pluralize(kebab)\n const pluralPascal = pluralizePascal(pascal)\n const moduleDir = join(modulesDir, plural)\n\n const files: string[] = []\n\n const write = async (relativePath: string, content: string) => {\n const fullPath = join(moduleDir, relativePath)\n await writeFileSafe(fullPath, content)\n files.push(fullPath)\n }\n\n // ── Module Index ────────────────────────────────────────────────────\n await write(\n 'index.ts',\n `/**\n * ${pascal} Module\n *\n * Self-contained feature module following Domain-Driven Design (DDD).\n * Registers dependencies in the DI container and declares HTTP routes.\n *\n * Structure:\n * presentation/ — HTTP controllers (entry points)\n * application/ — Use cases (orchestration) and DTOs (validation)\n * domain/ — Entities, value objects, repository interfaces, domain services\n * infrastructure/ — Repository implementations (in-memory, Drizzle, Prisma, etc.)\n */\nimport { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs-core'\nimport { buildRoutes } from '@forinda/kickjs-http'\nimport { ${pascal.toUpperCase()}_REPOSITORY } from './domain/repositories/${kebab}.repository'\nimport { ${repo === 'inmemory' ? `InMemory${pascal}Repository` : `Drizzle${pascal}Repository`} } from './infrastructure/repositories/${repo === 'inmemory' ? `in-memory-${kebab}` : `drizzle-${kebab}`}.repository'\nimport { ${pascal}Controller } from './presentation/${kebab}.controller'\n\n// Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container\nimport.meta.glob(\n ['./domain/services/**/*.ts', './application/use-cases/**/*.ts', '!./**/*.test.ts'],\n { eager: true },\n)\n\nexport class ${pascal}Module implements AppModule {\n /**\n * Register module dependencies in the DI container.\n * Bind repository interface tokens to their implementations here.\n * To swap implementations (e.g. in-memory -> Drizzle), change the factory target.\n */\n register(container: Container): void {\n container.registerFactory(${pascal.toUpperCase()}_REPOSITORY, () =>\n container.resolve(${repo === 'inmemory' ? `InMemory${pascal}Repository` : `Drizzle${pascal}Repository`}),\n )\n }\n\n /**\n * Declare HTTP routes for this module.\n * The path is prefixed with the global apiPrefix and version (e.g. /api/v1/${plural}).\n * Passing 'controller' enables automatic OpenAPI spec generation via SwaggerAdapter.\n */\n routes(): ModuleRoutes {\n return {\n path: '/${plural}',\n router: buildRoutes(${pascal}Controller),\n controller: ${pascal}Controller,\n }\n }\n}\n`,\n )\n\n // ── Controller ──────────────────────────────────────────────────────\n await write(\n `presentation/${kebab}.controller.ts`,\n `/**\n * ${pascal} Controller\n *\n * Presentation layer — handles HTTP requests and delegates to use cases.\n * Each method receives a RequestContext with typed body, params, and query.\n *\n * Decorators:\n * @Controller(path?) — registers this class as an HTTP controller\n * @Get/@Post/@Put/@Delete(path?, validation?) — defines routes with optional Zod validation\n * @Autowired() — injects dependencies lazily from the DI container\n * @Middleware(...handlers) — attach middleware at class or method level\n *\n * Add Swagger decorators (@ApiTags, @ApiOperation, @ApiResponse) from @forinda/kickjs-swagger\n * for automatic OpenAPI documentation.\n */\nimport { Controller, Get, Post, Put, Delete, Autowired } from '@forinda/kickjs-core'\nimport { RequestContext } from '@forinda/kickjs-http'\nimport { Create${pascal}UseCase } from '../application/use-cases/create-${kebab}.use-case'\nimport { Get${pascal}UseCase } from '../application/use-cases/get-${kebab}.use-case'\nimport { List${pluralPascal}UseCase } from '../application/use-cases/list-${plural}.use-case'\nimport { Update${pascal}UseCase } from '../application/use-cases/update-${kebab}.use-case'\nimport { Delete${pascal}UseCase } from '../application/use-cases/delete-${kebab}.use-case'\nimport { create${pascal}Schema } from '../application/dtos/create-${kebab}.dto'\nimport { update${pascal}Schema } from '../application/dtos/update-${kebab}.dto'\n\n@Controller()\nexport class ${pascal}Controller {\n @Autowired() private create${pascal}UseCase!: Create${pascal}UseCase\n @Autowired() private get${pascal}UseCase!: Get${pascal}UseCase\n @Autowired() private list${pluralPascal}UseCase!: List${pluralPascal}UseCase\n @Autowired() private update${pascal}UseCase!: Update${pascal}UseCase\n @Autowired() private delete${pascal}UseCase!: Delete${pascal}UseCase\n\n @Post('/', { body: create${pascal}Schema })\n async create(ctx: RequestContext) {\n const result = await this.create${pascal}UseCase.execute(ctx.body)\n ctx.created(result)\n }\n\n @Get('/')\n async list(ctx: RequestContext) {\n const result = await this.list${pluralPascal}UseCase.execute()\n ctx.json(result)\n }\n\n @Get('/:id')\n async getById(ctx: RequestContext) {\n const result = await this.get${pascal}UseCase.execute(ctx.params.id)\n if (!result) return ctx.notFound('${pascal} not found')\n ctx.json(result)\n }\n\n @Put('/:id', { body: update${pascal}Schema })\n async update(ctx: RequestContext) {\n const result = await this.update${pascal}UseCase.execute(ctx.params.id, ctx.body)\n ctx.json(result)\n }\n\n @Delete('/:id')\n async remove(ctx: RequestContext) {\n await this.delete${pascal}UseCase.execute(ctx.params.id)\n ctx.noContent()\n }\n}\n`,\n )\n\n // ── DTOs ────────────────────────────────────────────────────────────\n await write(\n `application/dtos/create-${kebab}.dto.ts`,\n `import { z } from 'zod'\n\n/**\n * Create ${pascal} DTO — Zod schema for validating POST request bodies.\n * This schema is passed to @Post('/', { body: create${pascal}Schema }) for automatic validation.\n * It also generates OpenAPI request body docs when SwaggerAdapter is used.\n *\n * Add more fields as needed. Supported Zod types:\n * z.string(), z.number(), z.boolean(), z.enum([...]),\n * z.array(), z.object(), .optional(), .default(), .transform()\n */\nexport const create${pascal}Schema = z.object({\n name: z.string().min(1, 'Name is required').max(200),\n})\n\nexport type Create${pascal}DTO = z.infer<typeof create${pascal}Schema>\n`,\n )\n\n await write(\n `application/dtos/update-${kebab}.dto.ts`,\n `import { z } from 'zod'\n\nexport const update${pascal}Schema = z.object({\n name: z.string().min(1).max(200).optional(),\n})\n\nexport type Update${pascal}DTO = z.infer<typeof update${pascal}Schema>\n`,\n )\n\n await write(\n `application/dtos/${kebab}-response.dto.ts`,\n `export interface ${pascal}ResponseDTO {\n id: string\n name: string\n createdAt: string\n updatedAt: string\n}\n`,\n )\n\n // ── Use Cases ───────────────────────────────────────────────────────\n const useCases = [\n {\n file: `create-${kebab}.use-case.ts`,\n content: `/**\n * Create ${pascal} Use Case\n *\n * Application layer — orchestrates a single business operation.\n * Use cases are thin: validate input (via DTO), call domain/repo, return response.\n * Keep business rules in the domain service, not here.\n */\nimport { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { Create${pascal}DTO } from '../dtos/create-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Create${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.create(dto)\n }\n}\n`,\n },\n {\n file: `get-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Get${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.repo.findById(id)\n }\n}\n`,\n },\n {\n file: `list-${plural}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class List${pluralPascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(): Promise<${pascal}ResponseDTO[]> {\n return this.repo.findAll()\n }\n}\n`,\n },\n {\n file: `update-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { Update${pascal}DTO } from '../dtos/update-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Update${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.update(id, dto)\n }\n}\n`,\n },\n {\n file: `delete-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\n\n@Service()\nexport class Delete${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string): Promise<void> {\n await this.repo.delete(id)\n }\n}\n`,\n },\n ]\n\n for (const uc of useCases) {\n await write(`application/use-cases/${uc.file}`, uc.content)\n }\n\n // ── Domain: Repository Interface ────────────────────────────────────\n await write(\n `domain/repositories/${kebab}.repository.ts`,\n `/**\n * ${pascal} Repository Interface\n *\n * Domain layer — defines the contract for data access.\n * The interface lives in the domain layer; implementations live in infrastructure.\n * This inversion of dependencies keeps the domain pure and testable.\n *\n * To swap implementations (e.g. in-memory -> Drizzle -> Prisma),\n * change the factory in the module's register() method.\n */\nimport type { ${pascal}ResponseDTO } from '../../application/dtos/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '../../application/dtos/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '../../application/dtos/update-${kebab}.dto'\n\nexport interface I${pascal}Repository {\n findById(id: string): Promise<${pascal}ResponseDTO | null>\n findAll(): Promise<${pascal}ResponseDTO[]>\n create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO>\n update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO>\n delete(id: string): Promise<void>\n}\n\nexport const ${pascal.toUpperCase()}_REPOSITORY = Symbol('I${pascal}Repository')\n`,\n )\n\n // ── Domain: Service ─────────────────────────────────────────────────\n await write(\n `domain/services/${kebab}-domain.service.ts`,\n `/**\n * ${pascal} Domain Service\n *\n * Domain layer — contains business rules that don't belong to a single entity.\n * Use this for cross-entity logic, validation rules, and domain invariants.\n * Keep it free of HTTP/framework concerns.\n */\nimport { Service, Inject, HttpException } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../repositories/${kebab}.repository'\n\n@Service()\nexport class ${pascal}DomainService {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async ensureExists(id: string): Promise<void> {\n const entity = await this.repo.findById(id)\n if (!entity) {\n throw HttpException.notFound('${pascal} not found')\n }\n }\n}\n`,\n )\n\n // ── Infrastructure: Repository Implementation ──────────────────────\n if (repo === 'inmemory') {\n await write(\n `infrastructure/repositories/in-memory-${kebab}.repository.ts`,\n `/**\n * In-Memory ${pascal} Repository\n *\n * Infrastructure layer — implements the repository interface using a Map.\n * Useful for prototyping and testing. Replace with a database implementation\n * (Drizzle, Prisma, etc.) for production use.\n *\n * @Repository() registers this class in the DI container as a singleton.\n */\nimport { randomUUID } from 'node:crypto'\nimport { Repository, HttpException } from '@forinda/kickjs-core'\nimport type { I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../../application/dtos/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '../../application/dtos/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '../../application/dtos/update-${kebab}.dto'\n\n@Repository()\nexport class InMemory${pascal}Repository implements I${pascal}Repository {\n private store = new Map<string, ${pascal}ResponseDTO>()\n\n async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.store.get(id) ?? null\n }\n\n async findAll(): Promise<${pascal}ResponseDTO[]> {\n return Array.from(this.store.values())\n }\n\n async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const now = new Date().toISOString()\n const entity: ${pascal}ResponseDTO = {\n id: randomUUID(),\n name: dto.name,\n createdAt: now,\n updatedAt: now,\n }\n this.store.set(entity.id, entity)\n return entity\n }\n\n async update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const existing = this.store.get(id)\n if (!existing) throw HttpException.notFound('${pascal} not found')\n const updated = { ...existing, ...dto, updatedAt: new Date().toISOString() }\n this.store.set(id, updated)\n return updated\n }\n\n async delete(id: string): Promise<void> {\n if (!this.store.has(id)) throw HttpException.notFound('${pascal} not found')\n this.store.delete(id)\n }\n}\n`,\n )\n }\n\n // ── Entity & Value Objects ──────────────────────────────────────────\n if (!noEntity && !minimal) {\n await write(\n `domain/entities/${kebab}.entity.ts`,\n `/**\n * ${pascal} Entity\n *\n * Domain layer — the core business object.\n * Uses a private constructor with static factory methods (create, reconstitute)\n * to enforce invariants. Properties are accessed via getters to maintain encapsulation.\n *\n * Patterns used:\n * - Private constructor: prevents direct instantiation\n * - create(): factory for new entities (generates ID, sets timestamps)\n * - reconstitute(): factory for rebuilding from persistence (no side effects)\n * - changeName(): mutation method that enforces business rules\n */\nimport { ${pascal}Id } from '../value-objects/${kebab}-id.vo'\n\ninterface ${pascal}Props {\n id: ${pascal}Id\n name: string\n createdAt: Date\n updatedAt: Date\n}\n\nexport class ${pascal} {\n private constructor(private props: ${pascal}Props) {}\n\n static create(params: { name: string }): ${pascal} {\n const now = new Date()\n return new ${pascal}({\n id: ${pascal}Id.create(),\n name: params.name,\n createdAt: now,\n updatedAt: now,\n })\n }\n\n static reconstitute(props: ${pascal}Props): ${pascal} {\n return new ${pascal}(props)\n }\n\n get id(): ${pascal}Id {\n return this.props.id\n }\n get name(): string {\n return this.props.name\n }\n get createdAt(): Date {\n return this.props.createdAt\n }\n get updatedAt(): Date {\n return this.props.updatedAt\n }\n\n changeName(name: string): void {\n if (!name || name.trim().length === 0) {\n throw new Error('Name cannot be empty')\n }\n this.props.name = name.trim()\n this.props.updatedAt = new Date()\n }\n\n toJSON() {\n return {\n id: this.props.id.toString(),\n name: this.props.name,\n createdAt: this.props.createdAt.toISOString(),\n updatedAt: this.props.updatedAt.toISOString(),\n }\n }\n}\n`,\n )\n\n await write(\n `domain/value-objects/${kebab}-id.vo.ts`,\n `/**\n * ${pascal} ID Value Object\n *\n * Domain layer — wraps a primitive ID with type safety and validation.\n * Value objects are immutable and compared by value, not reference.\n *\n * ${pascal}Id.create() — generate a new UUID\n * ${pascal}Id.from(id) — wrap an existing ID string (validates non-empty)\n * id.equals(other) — compare two IDs by value\n */\nimport { randomUUID } from 'node:crypto'\n\nexport class ${pascal}Id {\n private constructor(private readonly value: string) {}\n\n static create(): ${pascal}Id {\n return new ${pascal}Id(randomUUID())\n }\n\n static from(id: string): ${pascal}Id {\n if (!id || id.trim().length === 0) {\n throw new Error('${pascal}Id cannot be empty')\n }\n return new ${pascal}Id(id)\n }\n\n toString(): string {\n return this.value\n }\n\n equals(other: ${pascal}Id): boolean {\n return this.value === other.value\n }\n}\n`,\n )\n }\n\n // ── Auto-register in modules index ──────────────────────────────────\n await autoRegisterModule(modulesDir, pascal, plural)\n\n return files\n}\n\n/** Add the new module to src/modules/index.ts */\nasync function autoRegisterModule(\n modulesDir: string,\n pascal: string,\n plural: string,\n): Promise<void> {\n const indexPath = join(modulesDir, 'index.ts')\n const exists = await fileExists(indexPath)\n\n if (!exists) {\n await writeFileSafe(\n indexPath,\n `import type { AppModuleClass } from '@forinda/kickjs-core'\nimport { ${pascal}Module } from './${plural}'\n\nexport const modules: AppModuleClass[] = [${pascal}Module]\n`,\n )\n return\n }\n\n let content = await readFile(indexPath, 'utf-8')\n\n // Add import if not present\n const importLine = `import { ${pascal}Module } from './${plural}'`\n if (!content.includes(`${pascal}Module`)) {\n // Insert import after last existing import\n const lastImportIdx = content.lastIndexOf('import ')\n if (lastImportIdx !== -1) {\n const lineEnd = content.indexOf('\\n', lastImportIdx)\n content = content.slice(0, lineEnd + 1) + importLine + '\\n' + content.slice(lineEnd + 1)\n } else {\n content = importLine + '\\n' + content\n }\n\n // Add to modules array — handle both empty and existing entries\n // Match the array assignment: `= [...]` or `= [\\n...\\n]`\n content = content.replace(/(=\\s*\\[)([\\s\\S]*?)(])/, (_match, open, existing, close) => {\n const trimmed = existing.trim()\n if (!trimmed) {\n // Empty array: `= []`\n return `${open}${pascal}Module${close}`\n }\n // Existing entries: append with comma\n const needsComma = trimmed.endsWith(',') ? '' : ','\n return `${open}${existing.trimEnd()}${needsComma} ${pascal}Module${close}`\n })\n }\n\n await writeFile(indexPath, content, 'utf-8')\n}\n","import { writeFile, mkdir, access, readFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\n\n/** Write a file, creating parent directories if needed */\nexport async function writeFileSafe(filePath: string, content: string): Promise<void> {\n await mkdir(dirname(filePath), { recursive: true })\n await writeFile(filePath, content, 'utf-8')\n}\n\n/** Ensure a directory exists */\nexport async function ensureDirectory(dir: string): Promise<void> {\n await mkdir(dir, { recursive: true })\n}\n\n/** Check if a file exists */\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath)\n return true\n } catch {\n return false\n }\n}\n\n/** Read a JSON file */\nexport async function readJsonFile<T = any>(filePath: string): Promise<T> {\n const content = await readFile(filePath, 'utf-8')\n return JSON.parse(content)\n}\n","/** Convert a name to PascalCase */\nexport function toPascalCase(name: string): string {\n return name\n .replace(/[-_\\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))\n .replace(/^(.)/, (c) => c.toUpperCase())\n}\n\n/** Convert a name to camelCase */\nexport function toCamelCase(name: string): string {\n const pascal = toPascalCase(name)\n return pascal.charAt(0).toLowerCase() + pascal.slice(1)\n}\n\n/** Convert a name to kebab-case */\nexport function toKebabCase(name: string): string {\n return name\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\n\n/**\n * Pluralize a kebab-case name for directory/file names.\n * If already plural (ends in 's'), returns as-is.\n */\nexport function pluralize(name: string): string {\n if (name.endsWith('s')) return name\n if (name.endsWith('x') || name.endsWith('z')) return name + 'es'\n if (name.endsWith('sh') || name.endsWith('ch')) return name + 'es'\n if (name.endsWith('y') && !/[aeiou]y$/.test(name)) return name.slice(0, -1) + 'ies'\n return name + 's'\n}\n\n/**\n * Pluralize a PascalCase name for class identifiers.\n * If already plural (ends in 's'), returns as-is.\n * Used for `List${pluralPascal}UseCase` to avoid `ListUserssUseCase`.\n */\nexport function pluralizePascal(name: string): string {\n if (name.endsWith('s')) return name\n if (name.endsWith('x') || name.endsWith('z')) return name + 'es'\n if (name.endsWith('sh') || name.endsWith('ch')) return name + 'es'\n if (name.endsWith('y') && !/[aeiou]y$/i.test(name)) return name.slice(0, -1) + 'ies'\n return name + 's'\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateAdapterOptions {\n name: string\n outDir: string\n}\n\nexport async function generateAdapter(options: GenerateAdapterOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.adapter.ts`)\n await writeFileSafe(\n filePath,\n `import type { Express } from 'express'\nimport type { AppAdapter, AdapterMiddleware, Container } from '@forinda/kickjs-core'\n\nexport interface ${pascal}AdapterOptions {\n // Add your adapter configuration here\n}\n\n/**\n * ${pascal} adapter.\n *\n * Hooks into the Application lifecycle to add middleware, routes,\n * or external service connections.\n *\n * Usage:\n * bootstrap({\n * adapters: [new ${pascal}Adapter({ ... })],\n * })\n */\nexport class ${pascal}Adapter implements AppAdapter {\n name = '${pascal}Adapter'\n\n constructor(private options: ${pascal}AdapterOptions = {}) {}\n\n /**\n * Return middleware entries that the Application will mount.\n * Use \\`phase\\` to control where in the pipeline they run:\n * 'beforeGlobal' | 'afterGlobal' | 'beforeRoutes' | 'afterRoutes'\n */\n middleware(): AdapterMiddleware[] {\n return [\n // Example: add a custom header to all responses\n // {\n // phase: 'beforeGlobal',\n // handler: (_req: any, res: any, next: any) => {\n // res.setHeader('X-${pascal}', 'true')\n // next()\n // },\n // },\n // Example: scope middleware to a specific path\n // {\n // phase: 'beforeRoutes',\n // path: '/api/v1/admin',\n // handler: myAdminMiddleware(),\n // },\n ]\n }\n\n /**\n * Called before global middleware.\n * Use this to mount routes that bypass the middleware stack\n * (health checks, docs UI, static assets).\n */\n beforeMount(app: Express, container: Container): void {\n // Example: mount a status route\n // app.get('/${kebab}/status', (_req, res) => {\n // res.json({ status: 'ok' })\n // })\n }\n\n /**\n * Called after modules and routes are registered, before the server starts.\n * Use this for late-stage DI registrations or config validation.\n */\n beforeStart(app: Express, container: Container): void {\n // Example: register a service in the DI container\n // container.registerInstance(MY_TOKEN, new MyService(this.options))\n }\n\n /**\n * Called after the HTTP server is listening.\n * Use this to attach to the raw http.Server (Socket.IO, gRPC, etc).\n */\n afterStart(server: any, container: Container): void {\n // Example: attach Socket.IO\n // const io = new Server(server)\n // container.registerInstance(SOCKET_IO, io)\n }\n\n /**\n * Called on graceful shutdown. Clean up connections.\n */\n async shutdown(): Promise<void> {\n // Example: close a connection pool\n // await this.pool.end()\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\n\ninterface GenerateMiddlewareOptions {\n name: string\n outDir: string\n}\n\nexport async function generateMiddleware(options: GenerateMiddlewareOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const camel = toCamelCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.middleware.ts`)\n await writeFileSafe(\n filePath,\n `import type { Request, Response, NextFunction } from 'express'\n\nexport interface ${toPascalCase(name)}Options {\n // Add configuration options here\n}\n\n/**\n * ${toPascalCase(name)} middleware.\n *\n * Usage in bootstrap:\n * middleware: [${camel}()]\n *\n * Usage with adapter:\n * middleware() { return [{ handler: ${camel}(), phase: 'afterGlobal' }] }\n *\n * Usage with @Middleware decorator:\n * @Middleware(${camel}())\n */\nexport function ${camel}(options: ${toPascalCase(name)}Options = {}) {\n return (req: Request, res: Response, next: NextFunction) => {\n // Implement your middleware logic here\n next()\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\n\ninterface GenerateGuardOptions {\n name: string\n outDir: string\n}\n\nexport async function generateGuard(options: GenerateGuardOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const camel = toCamelCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.guard.ts`)\n await writeFileSafe(\n filePath,\n `import { Container, HttpException } from '@forinda/kickjs-core'\nimport type { RequestContext } from '@forinda/kickjs-http'\n\n/**\n * ${pascal} guard.\n *\n * Guards protect routes by checking conditions before the handler runs.\n * Return early with an error response to block access.\n *\n * Usage:\n * @Middleware(${camel}Guard)\n * @Get('/protected')\n * async handler(ctx: RequestContext) { ... }\n */\nexport async function ${camel}Guard(ctx: RequestContext, next: () => void): Promise<void> {\n // Example: check for an authorization header\n const header = ctx.headers.authorization\n if (!header?.startsWith('Bearer ')) {\n ctx.res.status(401).json({ message: 'Missing or invalid authorization header' })\n return\n }\n\n const token = header.slice(7)\n\n try {\n // Verify the token using a service from the DI container\n // const container = Container.getInstance()\n // const authService = container.resolve(AuthService)\n // const payload = authService.verifyToken(token)\n // ctx.set('auth', payload)\n\n next()\n } catch {\n ctx.res.status(401).json({ message: 'Invalid or expired token' })\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateServiceOptions {\n name: string\n outDir: string\n}\n\nexport async function generateService(options: GenerateServiceOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.service.ts`)\n await writeFileSafe(\n filePath,\n `import { Service } from '@forinda/kickjs-core'\n\n@Service()\nexport class ${pascal}Service {\n // Inject dependencies via constructor\n // constructor(\n // @Inject(MY_REPO) private readonly repo: IMyRepository,\n // ) {}\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateControllerOptions {\n name: string\n outDir: string\n}\n\nexport async function generateController(options: GenerateControllerOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.controller.ts`)\n await writeFileSafe(\n filePath,\n `import { Controller, Get, Post, Autowired } from '@forinda/kickjs-core'\nimport type { RequestContext } from '@forinda/kickjs-http'\n\n@Controller()\nexport class ${pascal}Controller {\n // @Autowired() private myService!: MyService\n\n @Get('/')\n async list(ctx: RequestContext) {\n ctx.json({ message: '${pascal} list' })\n }\n\n @Post('/')\n async create(ctx: RequestContext) {\n ctx.created({ message: '${pascal} created', data: ctx.body })\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\n\ninterface GenerateDtoOptions {\n name: string\n outDir: string\n}\n\nexport async function generateDto(options: GenerateDtoOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const camel = toCamelCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.dto.ts`)\n await writeFileSafe(\n filePath,\n `import { z } from 'zod'\n\nexport const ${camel}Schema = z.object({\n // Define your schema fields here\n name: z.string().min(1).max(200),\n})\n\nexport type ${pascal}DTO = z.infer<typeof ${camel}Schema>\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\n\ninterface InitProjectOptions {\n name: string\n directory: string\n packageManager?: 'pnpm' | 'npm' | 'yarn'\n}\n\n/** Scaffold a new KickJS project */\nexport async function initProject(options: InitProjectOptions): Promise<void> {\n const { name, directory, packageManager = 'pnpm' } = options\n const dir = directory\n\n console.log(`\\n Creating KickJS project: ${name}\\n`)\n\n // ── package.json ────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'package.json'),\n JSON.stringify(\n {\n name,\n version: '0.1.0',\n type: 'module',\n scripts: {\n dev: 'kick dev',\n 'dev:debug': 'kick dev:debug',\n build: 'kick build',\n start: 'kick start',\n test: 'vitest run',\n 'test:watch': 'vitest',\n typecheck: 'tsc --noEmit',\n lint: 'eslint src/',\n format: 'prettier --write src/',\n },\n dependencies: {\n '@forinda/kickjs-core': '^0.1.0',\n '@forinda/kickjs-http': '^0.1.0',\n '@forinda/kickjs-config': '^0.1.0',\n '@forinda/kickjs-swagger': '^0.1.0',\n express: '^5.1.0',\n 'reflect-metadata': '^0.2.2',\n zod: '^4.3.6',\n pino: '^10.3.1',\n 'pino-pretty': '^13.1.3',\n },\n devDependencies: {\n '@forinda/kickjs-cli': '^0.1.0',\n '@swc/core': '^1.7.28',\n '@types/express': '^5.0.6',\n '@types/node': '^24.5.2',\n 'unplugin-swc': '^1.5.9',\n vite: '^7.3.1',\n 'vite-node': '^5.3.0',\n vitest: '^3.2.4',\n typescript: '^5.9.2',\n prettier: '^3.8.1',\n },\n },\n null,\n 2,\n ),\n )\n\n // ── vite.config.ts — enables HMR + SWC for decorators ──────────────\n await writeFileSafe(\n join(dir, 'vite.config.ts'),\n `import { defineConfig } from 'vite'\nimport { resolve } from 'path'\nimport swc from 'unplugin-swc'\n\nexport default defineConfig({\n plugins: [swc.vite()],\n resolve: {\n alias: {\n '@': resolve(__dirname, 'src'),\n },\n },\n server: {\n watch: { usePolling: false },\n hmr: true,\n },\n build: {\n target: 'node20',\n ssr: true,\n outDir: 'dist',\n sourcemap: true,\n rollupOptions: {\n input: resolve(__dirname, 'src/index.ts'),\n output: { format: 'esm' },\n },\n },\n})\n`,\n )\n\n // ── tsconfig.json ───────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'tsconfig.json'),\n JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n lib: ['ES2022'],\n types: ['node'],\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n sourceMap: true,\n declaration: true,\n experimentalDecorators: true,\n emitDecoratorMetadata: true,\n outDir: 'dist',\n rootDir: 'src',\n paths: { '@/*': ['./src/*'] },\n },\n include: ['src'],\n },\n null,\n 2,\n ),\n )\n\n // ── .prettierrc ─────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, '.prettierrc'),\n JSON.stringify(\n {\n semi: false,\n singleQuote: true,\n trailingComma: 'all',\n printWidth: 100,\n tabWidth: 2,\n },\n null,\n 2,\n ),\n )\n\n // ── .gitignore ──────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, '.gitignore'),\n `node_modules/\ndist/\n.env\ncoverage/\n.DS_Store\n*.tsbuildinfo\n`,\n )\n\n // ── .env ────────────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, '.env'),\n `PORT=3000\nNODE_ENV=development\n`,\n )\n\n await writeFileSafe(\n join(dir, '.env.example'),\n `PORT=3000\nNODE_ENV=development\n`,\n )\n\n // ── src/index.ts — clean entry point with Swagger baked in ────────\n await writeFileSafe(\n join(dir, 'src/index.ts'),\n `import 'reflect-metadata'\nimport { bootstrap } from '@forinda/kickjs-http'\nimport { SwaggerAdapter } from '@forinda/kickjs-swagger'\nimport { modules } from './modules'\n\nbootstrap({\n modules,\n adapters: [\n new SwaggerAdapter({\n info: { title: '${name}', version: '0.1.0' },\n }),\n ],\n})\n`,\n )\n\n // ── src/modules/index.ts ────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'src/modules/index.ts'),\n `import type { AppModuleClass } from '@forinda/kickjs-core'\n\nexport const modules: AppModuleClass[] = []\n`,\n )\n\n // ── vitest.config.ts ────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'vitest.config.ts'),\n `import { defineConfig } from 'vitest/config'\nimport swc from 'unplugin-swc'\n\nexport default defineConfig({\n plugins: [swc.vite()],\n test: {\n globals: true,\n environment: 'node',\n include: ['src/**/*.test.ts'],\n },\n})\n`,\n )\n\n console.log(' Project scaffolded successfully!')\n console.log()\n console.log(' Next steps:')\n console.log(` cd ${name}`)\n console.log(` ${packageManager} install`)\n console.log(` kick g module user`)\n console.log(` kick dev`)\n console.log()\n console.log(' Commands:')\n console.log(' kick dev Start dev server with Vite HMR')\n console.log(' kick build Production build via Vite')\n console.log(' kick start Run production build')\n console.log(' kick g module X Generate a DDD module')\n console.log()\n}\n","import { readFile, access } from 'node:fs/promises'\nimport { join } from 'node:path'\n\n/** A custom command that developers can register via kick.config.ts */\nexport interface KickCommandDefinition {\n /** The command name (e.g. 'db:migrate', 'seed', 'proto:gen') */\n name: string\n /** Description shown in --help */\n description: string\n /**\n * Shell command(s) to run. Can be a single string or an array of\n * sequential steps. Use {args} as a placeholder for CLI arguments.\n *\n * @example\n * 'npx drizzle-kit migrate'\n * ['npx drizzle-kit generate', 'npx drizzle-kit migrate']\n */\n steps: string | string[]\n /** Optional aliases (e.g. ['migrate'] for 'db:migrate') */\n aliases?: string[]\n}\n\n/** Configuration for the kick.config.ts file */\nexport interface KickConfig {\n /** Where modules live (default: 'src/modules') */\n modulesDir?: string\n /** Default repository implementation for generators */\n defaultRepo?: 'drizzle' | 'inmemory' | 'prisma'\n /** Drizzle schema output directory */\n schemaDir?: string\n /** Custom commands that extend the CLI */\n commands?: KickCommandDefinition[]\n /** Code style overrides (auto-detected from prettier when possible) */\n style?: {\n semicolons?: boolean\n quotes?: 'single' | 'double'\n trailingComma?: 'all' | 'es5' | 'none'\n indent?: number\n }\n}\n\n/** Helper to define a type-safe kick.config.ts */\nexport function defineConfig(config: KickConfig): KickConfig {\n return config\n}\n\nconst CONFIG_FILES = ['kick.config.ts', 'kick.config.js', 'kick.config.mjs', 'kick.config.json']\n\n/** Load kick.config.* from the project root */\nexport async function loadKickConfig(cwd: string): Promise<KickConfig | null> {\n for (const filename of CONFIG_FILES) {\n const filepath = join(cwd, filename)\n try {\n await access(filepath)\n } catch {\n continue\n }\n\n if (filename.endsWith('.json')) {\n const content = await readFile(filepath, 'utf-8')\n return JSON.parse(content)\n }\n\n // For .ts/.js/.mjs — dynamic import (use file URL for cross-platform compat)\n try {\n const { pathToFileURL } = await import('node:url')\n const mod = await import(pathToFileURL(filepath).href)\n return mod.default ?? mod\n } catch (err) {\n if (filename.endsWith('.ts')) {\n console.warn(\n `Warning: Failed to load ${filename}. TypeScript config files require ` +\n 'a runtime loader (e.g. tsx, ts-node) or use kick.config.js/.mjs instead.',\n )\n }\n continue\n }\n }\n return null\n}\n"],"mappings":"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","names":["join","writeFile","mkdir","access","readFile","dirname","writeFileSafe","filePath","content","mkdir","dirname","recursive","writeFile","fileExists","filePath","access","toPascalCase","name","replace","_","c","toUpperCase","toCamelCase","pascal","charAt","toLowerCase","slice","toKebabCase","pluralize","endsWith","test","pluralizePascal","readFile","writeFile","generateModule","options","name","modulesDir","noEntity","noTests","repo","minimal","kebab","toKebabCase","pascal","toPascalCase","camel","toCamelCase","plural","pluralize","pluralPascal","pluralizePascal","moduleDir","join","files","write","relativePath","content","fullPath","writeFileSafe","push","toUpperCase","useCases","file","uc","autoRegisterModule","indexPath","exists","fileExists","readFile","importLine","includes","lastImportIdx","lastIndexOf","lineEnd","indexOf","slice","replace","_match","open","existing","close","trimmed","trim","needsComma","endsWith","trimEnd","writeFile","join","generateAdapter","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateMiddleware","options","name","outDir","kebab","toKebabCase","camel","toCamelCase","files","filePath","join","writeFileSafe","toPascalCase","push","join","generateGuard","options","name","outDir","kebab","toKebabCase","camel","toCamelCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateService","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateController","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateDto","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","camel","toCamelCase","files","filePath","join","writeFileSafe","push","join","initProject","options","name","directory","packageManager","dir","console","log","writeFileSafe","join","JSON","stringify","version","type","scripts","dev","build","start","test","typecheck","lint","format","dependencies","express","zod","pino","devDependencies","vite","vitest","typescript","prettier","compilerOptions","target","module","moduleResolution","lib","types","strict","esModuleInterop","skipLibCheck","sourceMap","declaration","experimentalDecorators","emitDecoratorMetadata","outDir","rootDir","paths","include","semi","singleQuote","trailingComma","printWidth","tabWidth","readFile","access","join","defineConfig","config","CONFIG_FILES","loadKickConfig","cwd","filename","filepath","join","access","endsWith","content","readFile","JSON","parse","pathToFileURL","mod","href","default","err","console","warn"]}
1
+ {"version":3,"sources":["../src/generators/module.ts","../src/utils/fs.ts","../src/utils/naming.ts","../src/generators/adapter.ts","../src/generators/middleware.ts","../src/generators/guard.ts","../src/generators/service.ts","../src/generators/controller.ts","../src/generators/dto.ts","../src/generators/project.ts","../src/config.ts"],"sourcesContent":["import { join } from 'node:path'\nimport { writeFileSafe, fileExists } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase, pluralize, pluralizePascal } from '../utils/naming'\nimport { readFile, writeFile } from 'node:fs/promises'\n\ninterface GenerateModuleOptions {\n name: string\n modulesDir: string\n noEntity?: boolean\n noTests?: boolean\n repo?: 'drizzle' | 'inmemory'\n minimal?: boolean\n}\n\n/**\n * Generate a full DDD module with all layers:\n * presentation/ — controller\n * application/ — use-cases, DTOs\n * domain/ — entity, value objects, repository interface, domain service\n * infrastructure/ — repository implementation\n */\nexport async function generateModule(options: GenerateModuleOptions): Promise<string[]> {\n const { name, modulesDir, noEntity, noTests, repo = 'inmemory', minimal } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const camel = toCamelCase(name)\n const plural = pluralize(kebab)\n const pluralPascal = pluralizePascal(pascal)\n const moduleDir = join(modulesDir, plural)\n\n const files: string[] = []\n\n const write = async (relativePath: string, content: string) => {\n const fullPath = join(moduleDir, relativePath)\n await writeFileSafe(fullPath, content)\n files.push(fullPath)\n }\n\n // ── Module Index ────────────────────────────────────────────────────\n await write(\n 'index.ts',\n `/**\n * ${pascal} Module\n *\n * Self-contained feature module following Domain-Driven Design (DDD).\n * Registers dependencies in the DI container and declares HTTP routes.\n *\n * Structure:\n * presentation/ — HTTP controllers (entry points)\n * application/ — Use cases (orchestration) and DTOs (validation)\n * domain/ — Entities, value objects, repository interfaces, domain services\n * infrastructure/ — Repository implementations (in-memory, Drizzle, Prisma, etc.)\n */\nimport { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs-core'\nimport { buildRoutes } from '@forinda/kickjs-http'\nimport { ${pascal.toUpperCase()}_REPOSITORY } from './domain/repositories/${kebab}.repository'\nimport { ${repo === 'inmemory' ? `InMemory${pascal}Repository` : `Drizzle${pascal}Repository`} } from './infrastructure/repositories/${repo === 'inmemory' ? `in-memory-${kebab}` : `drizzle-${kebab}`}.repository'\nimport { ${pascal}Controller } from './presentation/${kebab}.controller'\n\n// Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container\nimport.meta.glob(\n ['./domain/services/**/*.ts', './application/use-cases/**/*.ts', '!./**/*.test.ts'],\n { eager: true },\n)\n\nexport class ${pascal}Module implements AppModule {\n /**\n * Register module dependencies in the DI container.\n * Bind repository interface tokens to their implementations here.\n * To swap implementations (e.g. in-memory -> Drizzle), change the factory target.\n */\n register(container: Container): void {\n container.registerFactory(${pascal.toUpperCase()}_REPOSITORY, () =>\n container.resolve(${repo === 'inmemory' ? `InMemory${pascal}Repository` : `Drizzle${pascal}Repository`}),\n )\n }\n\n /**\n * Declare HTTP routes for this module.\n * The path is prefixed with the global apiPrefix and version (e.g. /api/v1/${plural}).\n * Passing 'controller' enables automatic OpenAPI spec generation via SwaggerAdapter.\n */\n routes(): ModuleRoutes {\n return {\n path: '/${plural}',\n router: buildRoutes(${pascal}Controller),\n controller: ${pascal}Controller,\n }\n }\n}\n`,\n )\n\n // ── Controller ──────────────────────────────────────────────────────\n await write(\n `presentation/${kebab}.controller.ts`,\n `/**\n * ${pascal} Controller\n *\n * Presentation layer — handles HTTP requests and delegates to use cases.\n * Each method receives a RequestContext with typed body, params, and query.\n *\n * Decorators:\n * @Controller(path?) — registers this class as an HTTP controller\n * @Get/@Post/@Put/@Delete(path?, validation?) — defines routes with optional Zod validation\n * @Autowired() — injects dependencies lazily from the DI container\n * @Middleware(...handlers) — attach middleware at class or method level\n *\n * Add Swagger decorators (@ApiTags, @ApiOperation, @ApiResponse) from @forinda/kickjs-swagger\n * for automatic OpenAPI documentation.\n */\nimport { Controller, Get, Post, Put, Delete, Autowired } from '@forinda/kickjs-core'\nimport { RequestContext } from '@forinda/kickjs-http'\nimport { Create${pascal}UseCase } from '../application/use-cases/create-${kebab}.use-case'\nimport { Get${pascal}UseCase } from '../application/use-cases/get-${kebab}.use-case'\nimport { List${pluralPascal}UseCase } from '../application/use-cases/list-${plural}.use-case'\nimport { Update${pascal}UseCase } from '../application/use-cases/update-${kebab}.use-case'\nimport { Delete${pascal}UseCase } from '../application/use-cases/delete-${kebab}.use-case'\nimport { create${pascal}Schema } from '../application/dtos/create-${kebab}.dto'\nimport { update${pascal}Schema } from '../application/dtos/update-${kebab}.dto'\n\n@Controller()\nexport class ${pascal}Controller {\n @Autowired() private create${pascal}UseCase!: Create${pascal}UseCase\n @Autowired() private get${pascal}UseCase!: Get${pascal}UseCase\n @Autowired() private list${pluralPascal}UseCase!: List${pluralPascal}UseCase\n @Autowired() private update${pascal}UseCase!: Update${pascal}UseCase\n @Autowired() private delete${pascal}UseCase!: Delete${pascal}UseCase\n\n @Post('/', { body: create${pascal}Schema })\n async create(ctx: RequestContext) {\n const result = await this.create${pascal}UseCase.execute(ctx.body)\n ctx.created(result)\n }\n\n @Get('/')\n async list(ctx: RequestContext) {\n const result = await this.list${pluralPascal}UseCase.execute()\n ctx.json(result)\n }\n\n @Get('/:id')\n async getById(ctx: RequestContext) {\n const result = await this.get${pascal}UseCase.execute(ctx.params.id)\n if (!result) return ctx.notFound('${pascal} not found')\n ctx.json(result)\n }\n\n @Put('/:id', { body: update${pascal}Schema })\n async update(ctx: RequestContext) {\n const result = await this.update${pascal}UseCase.execute(ctx.params.id, ctx.body)\n ctx.json(result)\n }\n\n @Delete('/:id')\n async remove(ctx: RequestContext) {\n await this.delete${pascal}UseCase.execute(ctx.params.id)\n ctx.noContent()\n }\n}\n`,\n )\n\n // ── DTOs ────────────────────────────────────────────────────────────\n await write(\n `application/dtos/create-${kebab}.dto.ts`,\n `import { z } from 'zod'\n\n/**\n * Create ${pascal} DTO — Zod schema for validating POST request bodies.\n * This schema is passed to @Post('/', { body: create${pascal}Schema }) for automatic validation.\n * It also generates OpenAPI request body docs when SwaggerAdapter is used.\n *\n * Add more fields as needed. Supported Zod types:\n * z.string(), z.number(), z.boolean(), z.enum([...]),\n * z.array(), z.object(), .optional(), .default(), .transform()\n */\nexport const create${pascal}Schema = z.object({\n name: z.string().min(1, 'Name is required').max(200),\n})\n\nexport type Create${pascal}DTO = z.infer<typeof create${pascal}Schema>\n`,\n )\n\n await write(\n `application/dtos/update-${kebab}.dto.ts`,\n `import { z } from 'zod'\n\nexport const update${pascal}Schema = z.object({\n name: z.string().min(1).max(200).optional(),\n})\n\nexport type Update${pascal}DTO = z.infer<typeof update${pascal}Schema>\n`,\n )\n\n await write(\n `application/dtos/${kebab}-response.dto.ts`,\n `export interface ${pascal}ResponseDTO {\n id: string\n name: string\n createdAt: string\n updatedAt: string\n}\n`,\n )\n\n // ── Use Cases ───────────────────────────────────────────────────────\n const useCases = [\n {\n file: `create-${kebab}.use-case.ts`,\n content: `/**\n * Create ${pascal} Use Case\n *\n * Application layer — orchestrates a single business operation.\n * Use cases are thin: validate input (via DTO), call domain/repo, return response.\n * Keep business rules in the domain service, not here.\n */\nimport { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { Create${pascal}DTO } from '../dtos/create-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Create${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.create(dto)\n }\n}\n`,\n },\n {\n file: `get-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Get${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.repo.findById(id)\n }\n}\n`,\n },\n {\n file: `list-${plural}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class List${pluralPascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(): Promise<${pascal}ResponseDTO[]> {\n return this.repo.findAll()\n }\n}\n`,\n },\n {\n file: `update-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { Update${pascal}DTO } from '../dtos/update-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Update${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.update(id, dto)\n }\n}\n`,\n },\n {\n file: `delete-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\n\n@Service()\nexport class Delete${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string): Promise<void> {\n await this.repo.delete(id)\n }\n}\n`,\n },\n ]\n\n for (const uc of useCases) {\n await write(`application/use-cases/${uc.file}`, uc.content)\n }\n\n // ── Domain: Repository Interface ────────────────────────────────────\n await write(\n `domain/repositories/${kebab}.repository.ts`,\n `/**\n * ${pascal} Repository Interface\n *\n * Domain layer — defines the contract for data access.\n * The interface lives in the domain layer; implementations live in infrastructure.\n * This inversion of dependencies keeps the domain pure and testable.\n *\n * To swap implementations (e.g. in-memory -> Drizzle -> Prisma),\n * change the factory in the module's register() method.\n */\nimport type { ${pascal}ResponseDTO } from '../../application/dtos/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '../../application/dtos/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '../../application/dtos/update-${kebab}.dto'\n\nexport interface I${pascal}Repository {\n findById(id: string): Promise<${pascal}ResponseDTO | null>\n findAll(): Promise<${pascal}ResponseDTO[]>\n create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO>\n update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO>\n delete(id: string): Promise<void>\n}\n\nexport const ${pascal.toUpperCase()}_REPOSITORY = Symbol('I${pascal}Repository')\n`,\n )\n\n // ── Domain: Service ─────────────────────────────────────────────────\n await write(\n `domain/services/${kebab}-domain.service.ts`,\n `/**\n * ${pascal} Domain Service\n *\n * Domain layer — contains business rules that don't belong to a single entity.\n * Use this for cross-entity logic, validation rules, and domain invariants.\n * Keep it free of HTTP/framework concerns.\n */\nimport { Service, Inject, HttpException } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../repositories/${kebab}.repository'\n\n@Service()\nexport class ${pascal}DomainService {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async ensureExists(id: string): Promise<void> {\n const entity = await this.repo.findById(id)\n if (!entity) {\n throw HttpException.notFound('${pascal} not found')\n }\n }\n}\n`,\n )\n\n // ── Infrastructure: Repository Implementation ──────────────────────\n if (repo === 'inmemory') {\n await write(\n `infrastructure/repositories/in-memory-${kebab}.repository.ts`,\n `/**\n * In-Memory ${pascal} Repository\n *\n * Infrastructure layer — implements the repository interface using a Map.\n * Useful for prototyping and testing. Replace with a database implementation\n * (Drizzle, Prisma, etc.) for production use.\n *\n * @Repository() registers this class in the DI container as a singleton.\n */\nimport { randomUUID } from 'node:crypto'\nimport { Repository, HttpException } from '@forinda/kickjs-core'\nimport type { I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../../application/dtos/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '../../application/dtos/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '../../application/dtos/update-${kebab}.dto'\n\n@Repository()\nexport class InMemory${pascal}Repository implements I${pascal}Repository {\n private store = new Map<string, ${pascal}ResponseDTO>()\n\n async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.store.get(id) ?? null\n }\n\n async findAll(): Promise<${pascal}ResponseDTO[]> {\n return Array.from(this.store.values())\n }\n\n async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const now = new Date().toISOString()\n const entity: ${pascal}ResponseDTO = {\n id: randomUUID(),\n name: dto.name,\n createdAt: now,\n updatedAt: now,\n }\n this.store.set(entity.id, entity)\n return entity\n }\n\n async update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const existing = this.store.get(id)\n if (!existing) throw HttpException.notFound('${pascal} not found')\n const updated = { ...existing, ...dto, updatedAt: new Date().toISOString() }\n this.store.set(id, updated)\n return updated\n }\n\n async delete(id: string): Promise<void> {\n if (!this.store.has(id)) throw HttpException.notFound('${pascal} not found')\n this.store.delete(id)\n }\n}\n`,\n )\n }\n\n // ── Entity & Value Objects ──────────────────────────────────────────\n if (!noEntity && !minimal) {\n await write(\n `domain/entities/${kebab}.entity.ts`,\n `/**\n * ${pascal} Entity\n *\n * Domain layer — the core business object.\n * Uses a private constructor with static factory methods (create, reconstitute)\n * to enforce invariants. Properties are accessed via getters to maintain encapsulation.\n *\n * Patterns used:\n * - Private constructor: prevents direct instantiation\n * - create(): factory for new entities (generates ID, sets timestamps)\n * - reconstitute(): factory for rebuilding from persistence (no side effects)\n * - changeName(): mutation method that enforces business rules\n */\nimport { ${pascal}Id } from '../value-objects/${kebab}-id.vo'\n\ninterface ${pascal}Props {\n id: ${pascal}Id\n name: string\n createdAt: Date\n updatedAt: Date\n}\n\nexport class ${pascal} {\n private constructor(private props: ${pascal}Props) {}\n\n static create(params: { name: string }): ${pascal} {\n const now = new Date()\n return new ${pascal}({\n id: ${pascal}Id.create(),\n name: params.name,\n createdAt: now,\n updatedAt: now,\n })\n }\n\n static reconstitute(props: ${pascal}Props): ${pascal} {\n return new ${pascal}(props)\n }\n\n get id(): ${pascal}Id {\n return this.props.id\n }\n get name(): string {\n return this.props.name\n }\n get createdAt(): Date {\n return this.props.createdAt\n }\n get updatedAt(): Date {\n return this.props.updatedAt\n }\n\n changeName(name: string): void {\n if (!name || name.trim().length === 0) {\n throw new Error('Name cannot be empty')\n }\n this.props.name = name.trim()\n this.props.updatedAt = new Date()\n }\n\n toJSON() {\n return {\n id: this.props.id.toString(),\n name: this.props.name,\n createdAt: this.props.createdAt.toISOString(),\n updatedAt: this.props.updatedAt.toISOString(),\n }\n }\n}\n`,\n )\n\n await write(\n `domain/value-objects/${kebab}-id.vo.ts`,\n `/**\n * ${pascal} ID Value Object\n *\n * Domain layer — wraps a primitive ID with type safety and validation.\n * Value objects are immutable and compared by value, not reference.\n *\n * ${pascal}Id.create() — generate a new UUID\n * ${pascal}Id.from(id) — wrap an existing ID string (validates non-empty)\n * id.equals(other) — compare two IDs by value\n */\nimport { randomUUID } from 'node:crypto'\n\nexport class ${pascal}Id {\n private constructor(private readonly value: string) {}\n\n static create(): ${pascal}Id {\n return new ${pascal}Id(randomUUID())\n }\n\n static from(id: string): ${pascal}Id {\n if (!id || id.trim().length === 0) {\n throw new Error('${pascal}Id cannot be empty')\n }\n return new ${pascal}Id(id)\n }\n\n toString(): string {\n return this.value\n }\n\n equals(other: ${pascal}Id): boolean {\n return this.value === other.value\n }\n}\n`,\n )\n }\n\n // ── Auto-register in modules index ──────────────────────────────────\n await autoRegisterModule(modulesDir, pascal, plural)\n\n return files\n}\n\n/** Add the new module to src/modules/index.ts */\nasync function autoRegisterModule(\n modulesDir: string,\n pascal: string,\n plural: string,\n): Promise<void> {\n const indexPath = join(modulesDir, 'index.ts')\n const exists = await fileExists(indexPath)\n\n if (!exists) {\n await writeFileSafe(\n indexPath,\n `import type { AppModuleClass } from '@forinda/kickjs-core'\nimport { ${pascal}Module } from './${plural}'\n\nexport const modules: AppModuleClass[] = [${pascal}Module]\n`,\n )\n return\n }\n\n let content = await readFile(indexPath, 'utf-8')\n\n // Add import if not present\n const importLine = `import { ${pascal}Module } from './${plural}'`\n if (!content.includes(`${pascal}Module`)) {\n // Insert import after last existing import\n const lastImportIdx = content.lastIndexOf('import ')\n if (lastImportIdx !== -1) {\n const lineEnd = content.indexOf('\\n', lastImportIdx)\n content = content.slice(0, lineEnd + 1) + importLine + '\\n' + content.slice(lineEnd + 1)\n } else {\n content = importLine + '\\n' + content\n }\n\n // Add to modules array — handle both empty and existing entries\n // Match the array assignment: `= [...]` or `= [\\n...\\n]`\n content = content.replace(/(=\\s*\\[)([\\s\\S]*?)(])/, (_match, open, existing, close) => {\n const trimmed = existing.trim()\n if (!trimmed) {\n // Empty array: `= []`\n return `${open}${pascal}Module${close}`\n }\n // Existing entries: append with comma\n const needsComma = trimmed.endsWith(',') ? '' : ','\n return `${open}${existing.trimEnd()}${needsComma} ${pascal}Module${close}`\n })\n }\n\n await writeFile(indexPath, content, 'utf-8')\n}\n","import { writeFile, mkdir, access, readFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\n\n/** Write a file, creating parent directories if needed */\nexport async function writeFileSafe(filePath: string, content: string): Promise<void> {\n await mkdir(dirname(filePath), { recursive: true })\n await writeFile(filePath, content, 'utf-8')\n}\n\n/** Ensure a directory exists */\nexport async function ensureDirectory(dir: string): Promise<void> {\n await mkdir(dir, { recursive: true })\n}\n\n/** Check if a file exists */\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath)\n return true\n } catch {\n return false\n }\n}\n\n/** Read a JSON file */\nexport async function readJsonFile<T = any>(filePath: string): Promise<T> {\n const content = await readFile(filePath, 'utf-8')\n return JSON.parse(content)\n}\n","/** Convert a name to PascalCase */\nexport function toPascalCase(name: string): string {\n return name\n .replace(/[-_\\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))\n .replace(/^(.)/, (c) => c.toUpperCase())\n}\n\n/** Convert a name to camelCase */\nexport function toCamelCase(name: string): string {\n const pascal = toPascalCase(name)\n return pascal.charAt(0).toLowerCase() + pascal.slice(1)\n}\n\n/** Convert a name to kebab-case */\nexport function toKebabCase(name: string): string {\n return name\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\n\n/**\n * Pluralize a kebab-case name for directory/file names.\n * If already plural (ends in 's'), returns as-is.\n */\nexport function pluralize(name: string): string {\n if (name.endsWith('s')) return name\n if (name.endsWith('x') || name.endsWith('z')) return name + 'es'\n if (name.endsWith('sh') || name.endsWith('ch')) return name + 'es'\n if (name.endsWith('y') && !/[aeiou]y$/.test(name)) return name.slice(0, -1) + 'ies'\n return name + 's'\n}\n\n/**\n * Pluralize a PascalCase name for class identifiers.\n * If already plural (ends in 's'), returns as-is.\n * Used for `List${pluralPascal}UseCase` to avoid `ListUserssUseCase`.\n */\nexport function pluralizePascal(name: string): string {\n if (name.endsWith('s')) return name\n if (name.endsWith('x') || name.endsWith('z')) return name + 'es'\n if (name.endsWith('sh') || name.endsWith('ch')) return name + 'es'\n if (name.endsWith('y') && !/[aeiou]y$/i.test(name)) return name.slice(0, -1) + 'ies'\n return name + 's'\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateAdapterOptions {\n name: string\n outDir: string\n}\n\nexport async function generateAdapter(options: GenerateAdapterOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.adapter.ts`)\n await writeFileSafe(\n filePath,\n `import type { Express } from 'express'\nimport type { AppAdapter, AdapterMiddleware, Container } from '@forinda/kickjs-core'\n\nexport interface ${pascal}AdapterOptions {\n // Add your adapter configuration here\n}\n\n/**\n * ${pascal} adapter.\n *\n * Hooks into the Application lifecycle to add middleware, routes,\n * or external service connections.\n *\n * Usage:\n * bootstrap({\n * adapters: [new ${pascal}Adapter({ ... })],\n * })\n */\nexport class ${pascal}Adapter implements AppAdapter {\n name = '${pascal}Adapter'\n\n constructor(private options: ${pascal}AdapterOptions = {}) {}\n\n /**\n * Return middleware entries that the Application will mount.\n * Use \\`phase\\` to control where in the pipeline they run:\n * 'beforeGlobal' | 'afterGlobal' | 'beforeRoutes' | 'afterRoutes'\n */\n middleware(): AdapterMiddleware[] {\n return [\n // Example: add a custom header to all responses\n // {\n // phase: 'beforeGlobal',\n // handler: (_req: any, res: any, next: any) => {\n // res.setHeader('X-${pascal}', 'true')\n // next()\n // },\n // },\n // Example: scope middleware to a specific path\n // {\n // phase: 'beforeRoutes',\n // path: '/api/v1/admin',\n // handler: myAdminMiddleware(),\n // },\n ]\n }\n\n /**\n * Called before global middleware.\n * Use this to mount routes that bypass the middleware stack\n * (health checks, docs UI, static assets).\n */\n beforeMount(app: Express, container: Container): void {\n // Example: mount a status route\n // app.get('/${kebab}/status', (_req, res) => {\n // res.json({ status: 'ok' })\n // })\n }\n\n /**\n * Called after modules and routes are registered, before the server starts.\n * Use this for late-stage DI registrations or config validation.\n */\n beforeStart(app: Express, container: Container): void {\n // Example: register a service in the DI container\n // container.registerInstance(MY_TOKEN, new MyService(this.options))\n }\n\n /**\n * Called after the HTTP server is listening.\n * Use this to attach to the raw http.Server (Socket.IO, gRPC, etc).\n */\n afterStart(server: any, container: Container): void {\n // Example: attach Socket.IO\n // const io = new Server(server)\n // container.registerInstance(SOCKET_IO, io)\n }\n\n /**\n * Called on graceful shutdown. Clean up connections.\n */\n async shutdown(): Promise<void> {\n // Example: close a connection pool\n // await this.pool.end()\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\n\ninterface GenerateMiddlewareOptions {\n name: string\n outDir: string\n}\n\nexport async function generateMiddleware(options: GenerateMiddlewareOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const camel = toCamelCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.middleware.ts`)\n await writeFileSafe(\n filePath,\n `import type { Request, Response, NextFunction } from 'express'\n\nexport interface ${toPascalCase(name)}Options {\n // Add configuration options here\n}\n\n/**\n * ${toPascalCase(name)} middleware.\n *\n * Usage in bootstrap:\n * middleware: [${camel}()]\n *\n * Usage with adapter:\n * middleware() { return [{ handler: ${camel}(), phase: 'afterGlobal' }] }\n *\n * Usage with @Middleware decorator:\n * @Middleware(${camel}())\n */\nexport function ${camel}(options: ${toPascalCase(name)}Options = {}) {\n return (req: Request, res: Response, next: NextFunction) => {\n // Implement your middleware logic here\n next()\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\n\ninterface GenerateGuardOptions {\n name: string\n outDir: string\n}\n\nexport async function generateGuard(options: GenerateGuardOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const camel = toCamelCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.guard.ts`)\n await writeFileSafe(\n filePath,\n `import { Container, HttpException } from '@forinda/kickjs-core'\nimport type { RequestContext } from '@forinda/kickjs-http'\n\n/**\n * ${pascal} guard.\n *\n * Guards protect routes by checking conditions before the handler runs.\n * Return early with an error response to block access.\n *\n * Usage:\n * @Middleware(${camel}Guard)\n * @Get('/protected')\n * async handler(ctx: RequestContext) { ... }\n */\nexport async function ${camel}Guard(ctx: RequestContext, next: () => void): Promise<void> {\n // Example: check for an authorization header\n const header = ctx.headers.authorization\n if (!header?.startsWith('Bearer ')) {\n ctx.res.status(401).json({ message: 'Missing or invalid authorization header' })\n return\n }\n\n const token = header.slice(7)\n\n try {\n // Verify the token using a service from the DI container\n // const container = Container.getInstance()\n // const authService = container.resolve(AuthService)\n // const payload = authService.verifyToken(token)\n // ctx.set('auth', payload)\n\n next()\n } catch {\n ctx.res.status(401).json({ message: 'Invalid or expired token' })\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateServiceOptions {\n name: string\n outDir: string\n}\n\nexport async function generateService(options: GenerateServiceOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.service.ts`)\n await writeFileSafe(\n filePath,\n `import { Service } from '@forinda/kickjs-core'\n\n@Service()\nexport class ${pascal}Service {\n // Inject dependencies via constructor\n // constructor(\n // @Inject(MY_REPO) private readonly repo: IMyRepository,\n // ) {}\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateControllerOptions {\n name: string\n outDir: string\n}\n\nexport async function generateController(options: GenerateControllerOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.controller.ts`)\n await writeFileSafe(\n filePath,\n `import { Controller, Get, Post, Autowired } from '@forinda/kickjs-core'\nimport type { RequestContext } from '@forinda/kickjs-http'\n\n@Controller()\nexport class ${pascal}Controller {\n // @Autowired() private myService!: MyService\n\n @Get('/')\n async list(ctx: RequestContext) {\n ctx.json({ message: '${pascal} list' })\n }\n\n @Post('/')\n async create(ctx: RequestContext) {\n ctx.created({ message: '${pascal} created', data: ctx.body })\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\n\ninterface GenerateDtoOptions {\n name: string\n outDir: string\n}\n\nexport async function generateDto(options: GenerateDtoOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const camel = toCamelCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.dto.ts`)\n await writeFileSafe(\n filePath,\n `import { z } from 'zod'\n\nexport const ${camel}Schema = z.object({\n // Define your schema fields here\n name: z.string().min(1).max(200),\n})\n\nexport type ${pascal}DTO = z.infer<typeof ${camel}Schema>\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { execSync } from 'node:child_process'\nimport { writeFileSafe } from '../utils/fs'\n\ninterface InitProjectOptions {\n name: string\n directory: string\n packageManager?: 'pnpm' | 'npm' | 'yarn'\n initGit?: boolean\n installDeps?: boolean\n}\n\n/** Scaffold a new KickJS project */\nexport async function initProject(options: InitProjectOptions): Promise<void> {\n const { name, directory, packageManager = 'pnpm' } = options\n const dir = directory\n\n console.log(`\\n Creating KickJS project: ${name}\\n`)\n\n // ── package.json ────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'package.json'),\n JSON.stringify(\n {\n name,\n version: '0.1.0',\n type: 'module',\n scripts: {\n dev: 'kick dev',\n 'dev:debug': 'kick dev:debug',\n build: 'kick build',\n start: 'kick start',\n test: 'vitest run',\n 'test:watch': 'vitest',\n typecheck: 'tsc --noEmit',\n lint: 'eslint src/',\n format: 'prettier --write src/',\n },\n dependencies: {\n '@forinda/kickjs-core': '^0.1.0',\n '@forinda/kickjs-http': '^0.1.0',\n '@forinda/kickjs-config': '^0.1.0',\n '@forinda/kickjs-swagger': '^0.1.0',\n express: '^5.1.0',\n 'reflect-metadata': '^0.2.2',\n zod: '^4.3.6',\n pino: '^10.3.1',\n 'pino-pretty': '^13.1.3',\n },\n devDependencies: {\n '@forinda/kickjs-cli': '^0.1.0',\n '@swc/core': '^1.7.28',\n '@types/express': '^5.0.6',\n '@types/node': '^24.5.2',\n 'unplugin-swc': '^1.5.9',\n vite: '^7.3.1',\n 'vite-node': '^5.3.0',\n vitest: '^3.2.4',\n typescript: '^5.9.2',\n prettier: '^3.8.1',\n },\n },\n null,\n 2,\n ),\n )\n\n // ── vite.config.ts — enables HMR + SWC for decorators ──────────────\n await writeFileSafe(\n join(dir, 'vite.config.ts'),\n `import { defineConfig } from 'vite'\nimport { resolve } from 'path'\nimport swc from 'unplugin-swc'\n\nexport default defineConfig({\n plugins: [swc.vite()],\n resolve: {\n alias: {\n '@': resolve(__dirname, 'src'),\n },\n },\n server: {\n watch: { usePolling: false },\n hmr: true,\n },\n build: {\n target: 'node20',\n ssr: true,\n outDir: 'dist',\n sourcemap: true,\n rollupOptions: {\n input: resolve(__dirname, 'src/index.ts'),\n output: { format: 'esm' },\n },\n },\n})\n`,\n )\n\n // ── tsconfig.json ───────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'tsconfig.json'),\n JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n lib: ['ES2022'],\n types: ['node'],\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n sourceMap: true,\n declaration: true,\n experimentalDecorators: true,\n emitDecoratorMetadata: true,\n outDir: 'dist',\n rootDir: 'src',\n paths: { '@/*': ['./src/*'] },\n },\n include: ['src'],\n },\n null,\n 2,\n ),\n )\n\n // ── .prettierrc ─────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, '.prettierrc'),\n JSON.stringify(\n {\n semi: false,\n singleQuote: true,\n trailingComma: 'all',\n printWidth: 100,\n tabWidth: 2,\n },\n null,\n 2,\n ),\n )\n\n // ── .gitignore ──────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, '.gitignore'),\n `node_modules/\ndist/\n.env\ncoverage/\n.DS_Store\n*.tsbuildinfo\n`,\n )\n\n // ── .env ────────────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, '.env'),\n `PORT=3000\nNODE_ENV=development\n`,\n )\n\n await writeFileSafe(\n join(dir, '.env.example'),\n `PORT=3000\nNODE_ENV=development\n`,\n )\n\n // ── src/index.ts — clean entry point with Swagger baked in ────────\n await writeFileSafe(\n join(dir, 'src/index.ts'),\n `import 'reflect-metadata'\nimport { bootstrap } from '@forinda/kickjs-http'\nimport { SwaggerAdapter } from '@forinda/kickjs-swagger'\nimport { modules } from './modules'\n\nbootstrap({\n modules,\n adapters: [\n new SwaggerAdapter({\n info: { title: '${name}', version: '0.1.0' },\n }),\n ],\n})\n`,\n )\n\n // ── src/modules/index.ts ────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'src/modules/index.ts'),\n `import type { AppModuleClass } from '@forinda/kickjs-core'\n\nexport const modules: AppModuleClass[] = []\n`,\n )\n\n // ── kick.config.ts — CLI configuration ─────────────────────────────\n await writeFileSafe(\n join(dir, 'kick.config.ts'),\n `import { defineConfig } from '@forinda/kickjs-cli'\n\nexport default defineConfig({\n modulesDir: 'src/modules',\n defaultRepo: 'inmemory',\n\n commands: [\n {\n name: 'test',\n description: 'Run tests with Vitest',\n steps: 'npx vitest run',\n },\n {\n name: 'format',\n description: 'Format code with Prettier',\n steps: 'npx prettier --write src/',\n },\n {\n name: 'format:check',\n description: 'Check formatting without writing',\n steps: 'npx prettier --check src/',\n },\n {\n name: 'check',\n description: 'Run typecheck + format check',\n steps: ['npx tsc --noEmit', 'npx prettier --check src/'],\n aliases: ['verify', 'ci'],\n },\n ],\n})\n`,\n )\n\n // ── vitest.config.ts ────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'vitest.config.ts'),\n `import { defineConfig } from 'vitest/config'\nimport swc from 'unplugin-swc'\n\nexport default defineConfig({\n plugins: [swc.vite()],\n test: {\n globals: true,\n environment: 'node',\n include: ['src/**/*.test.ts'],\n },\n})\n`,\n )\n\n // ── Git Init ─────────────────────────────────────────────────────────\n if (options.initGit) {\n try {\n execSync('git init', { cwd: dir, stdio: 'pipe' })\n execSync('git add -A', { cwd: dir, stdio: 'pipe' })\n execSync('git commit -m \"chore: initial commit from kick new\"', {\n cwd: dir,\n stdio: 'pipe',\n })\n console.log(' Git repository initialized')\n } catch {\n console.log(' Warning: git init failed (git may not be installed)')\n }\n }\n\n // ── Install Dependencies ────────────────────────────────────────────\n if (options.installDeps) {\n console.log(`\\n Installing dependencies with ${packageManager}...\\n`)\n try {\n execSync(`${packageManager} install`, { cwd: dir, stdio: 'inherit' })\n console.log('\\n Dependencies installed successfully!')\n } catch {\n console.log(`\\n Warning: ${packageManager} install failed. Run it manually.`)\n }\n }\n\n console.log('\\n Project scaffolded successfully!')\n console.log()\n\n const needsCd = dir !== process.cwd()\n console.log(' Next steps:')\n if (needsCd) console.log(` cd ${name}`)\n if (!options.installDeps) console.log(` ${packageManager} install`)\n console.log(' kick g module user')\n console.log(' kick dev')\n console.log()\n console.log(' Commands:')\n console.log(' kick dev Start dev server with Vite HMR')\n console.log(' kick build Production build via Vite')\n console.log(' kick start Run production build')\n console.log(' kick g module X Generate a DDD module')\n console.log()\n}\n","import { readFile, access } from 'node:fs/promises'\nimport { join } from 'node:path'\n\n/** A custom command that developers can register via kick.config.ts */\nexport interface KickCommandDefinition {\n /** The command name (e.g. 'db:migrate', 'seed', 'proto:gen') */\n name: string\n /** Description shown in --help */\n description: string\n /**\n * Shell command(s) to run. Can be a single string or an array of\n * sequential steps. Use {args} as a placeholder for CLI arguments.\n *\n * @example\n * 'npx drizzle-kit migrate'\n * ['npx drizzle-kit generate', 'npx drizzle-kit migrate']\n */\n steps: string | string[]\n /** Optional aliases (e.g. ['migrate'] for 'db:migrate') */\n aliases?: string[]\n}\n\n/** Configuration for the kick.config.ts file */\nexport interface KickConfig {\n /** Where modules live (default: 'src/modules') */\n modulesDir?: string\n /** Default repository implementation for generators */\n defaultRepo?: 'drizzle' | 'inmemory' | 'prisma'\n /** Drizzle schema output directory */\n schemaDir?: string\n /** Custom commands that extend the CLI */\n commands?: KickCommandDefinition[]\n /** Code style overrides (auto-detected from prettier when possible) */\n style?: {\n semicolons?: boolean\n quotes?: 'single' | 'double'\n trailingComma?: 'all' | 'es5' | 'none'\n indent?: number\n }\n}\n\n/** Helper to define a type-safe kick.config.ts */\nexport function defineConfig(config: KickConfig): KickConfig {\n return config\n}\n\nconst CONFIG_FILES = ['kick.config.ts', 'kick.config.js', 'kick.config.mjs', 'kick.config.json']\n\n/** Load kick.config.* from the project root */\nexport async function loadKickConfig(cwd: string): Promise<KickConfig | null> {\n for (const filename of CONFIG_FILES) {\n const filepath = join(cwd, filename)\n try {\n await access(filepath)\n } catch {\n continue\n }\n\n if (filename.endsWith('.json')) {\n const content = await readFile(filepath, 'utf-8')\n return JSON.parse(content)\n }\n\n // For .ts/.js/.mjs — dynamic import (use file URL for cross-platform compat)\n try {\n const { pathToFileURL } = await import('node:url')\n const mod = await import(pathToFileURL(filepath).href)\n return mod.default ?? mod\n } catch (err) {\n if (filename.endsWith('.ts')) {\n console.warn(\n `Warning: Failed to load ${filename}. TypeScript config files require ` +\n 'a runtime loader (e.g. tsx, ts-node) or use kick.config.js/.mjs instead.',\n )\n }\n continue\n }\n }\n return null\n}\n"],"mappings":"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","names":["join","writeFile","mkdir","access","readFile","dirname","writeFileSafe","filePath","content","mkdir","dirname","recursive","writeFile","fileExists","filePath","access","toPascalCase","name","replace","_","c","toUpperCase","toCamelCase","pascal","charAt","toLowerCase","slice","toKebabCase","pluralize","endsWith","test","pluralizePascal","readFile","writeFile","generateModule","options","name","modulesDir","noEntity","noTests","repo","minimal","kebab","toKebabCase","pascal","toPascalCase","camel","toCamelCase","plural","pluralize","pluralPascal","pluralizePascal","moduleDir","join","files","write","relativePath","content","fullPath","writeFileSafe","push","toUpperCase","useCases","file","uc","autoRegisterModule","indexPath","exists","fileExists","readFile","importLine","includes","lastImportIdx","lastIndexOf","lineEnd","indexOf","slice","replace","_match","open","existing","close","trimmed","trim","needsComma","endsWith","trimEnd","writeFile","join","generateAdapter","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateMiddleware","options","name","outDir","kebab","toKebabCase","camel","toCamelCase","files","filePath","join","writeFileSafe","toPascalCase","push","join","generateGuard","options","name","outDir","kebab","toKebabCase","camel","toCamelCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateService","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateController","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateDto","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","camel","toCamelCase","files","filePath","join","writeFileSafe","push","join","execSync","initProject","options","name","directory","packageManager","dir","console","log","writeFileSafe","join","JSON","stringify","version","type","scripts","dev","build","start","test","typecheck","lint","format","dependencies","express","zod","pino","devDependencies","vite","vitest","typescript","prettier","compilerOptions","target","module","moduleResolution","lib","types","strict","esModuleInterop","skipLibCheck","sourceMap","declaration","experimentalDecorators","emitDecoratorMetadata","outDir","rootDir","paths","include","semi","singleQuote","trailingComma","printWidth","tabWidth","initGit","execSync","cwd","stdio","installDeps","needsCd","process","readFile","access","join","defineConfig","config","CONFIG_FILES","loadKickConfig","cwd","filename","filepath","join","access","endsWith","content","readFile","JSON","parse","pathToFileURL","mod","href","default","err","console","warn"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forinda/kickjs-cli",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "CLI for KickJS — project scaffolding, DDD module generation, dev/build/start",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -35,6 +35,7 @@
35
35
  "engines": {
36
36
  "node": ">=20.0"
37
37
  },
38
+ "homepage": "https://forinda.github.io/kick-js/",
38
39
  "scripts": {
39
40
  "build": "tsup",
40
41
  "dev": "tsup --watch",