{"version":3,"file":"doctor-Dj_h900X.mjs","names":["colors","colors"],"sources":["../src/utils/naming.ts","../src/utils/regex.ts","../src/generators/templates/module-index.ts","../src/generators/templates/controller.ts","../src/generators/templates/dtos.ts","../src/generators/templates/repository.ts","../src/generators/templates/tests.ts","../src/generators/templates/rest-service.ts","../src/generators/templates/project-app.ts","../src/generators/patterns/minimal.ts","../src/generators/patterns/rest.ts","../src/generators/module.ts","../src/generators/adapter.ts","../src/utils/resolve-out-dir.ts","../src/generators/middleware.ts","../src/generators/guard.ts","../src/generators/service.ts","../src/generators/controller.ts","../src/generators/dto.ts","../src/generators/templates/project-config.ts","../src/commands/add.ts","../src/generators/project.ts","../src/commands/typegen-error-reporter.ts","../src/typegen/dev-watcher.ts","../src/generator-extension/context.ts","../src/generator-extension/discover.ts","../src/generator-extension/dispatch.ts","../src/commands/doctor.ts"],"sourcesContent":["import pkg from 'pluralize'\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 * Uses the `pluralize` npm package for correct English pluralization\n * including irregulars (person → people, status → statuses, child → children).\n */\nexport function pluralize(name: string): string {\n  return pkg.plural(name)\n}\n\n/**\n * Pluralize a PascalCase name for class identifiers.\n * Used for `List${pluralPascal}UseCase` to avoid `ListUserssUseCase`.\n */\nexport function pluralizePascal(name: string): string {\n  return pkg.plural(name)\n}\n","/**\n * Escape a string for safe interpolation into a `new RegExp(...)`\n * source. Each character that has special meaning inside a regex\n * pattern (`.`, `*`, `+`, `?`, `^`, `$`, `{`, `}`, `(`, `)`, `|`,\n * `[`, `]`, `\\`) is prefixed with a backslash so it's matched\n * literally instead of treated as a metacharacter.\n *\n * Used everywhere the codegen / removal flow builds a regex from\n * adopter-provided identifiers (`pascal`, `plural`, etc). Names\n * coming through `toPascalCase` / `toKebabCase` are already\n * alphanumeric in practice, but escaping defensively keeps the\n * code correct if upstream sanitization ever loosens.\n */\nexport function escapeRegex(input: string): string {\n  return input.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n","import type { RepoType } from '../module'\nimport type { ModuleStyle, TemplateContext } from './types'\n\nconst repoLabelMap: Record<string, string> = {\n  inmemory: 'in-memory',\n  drizzle: 'Drizzle',\n  prisma: 'Prisma',\n}\n\nfunction toPascalRepoType(repo: string): string {\n  return (\n    repo.charAt(0).toUpperCase() +\n    repo.slice(1).replace(/-([a-z])/g, (_, c: string) => c.toUpperCase())\n  )\n}\n\nfunction toKebabRepoType(repo: string): string {\n  return repo.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()\n}\n\nfunction repoLabel(repo: RepoType): string {\n  return repoLabelMap[repo] ?? toPascalRepoType(repo)\n}\n\nfunction repoMaps(pascal: string, kebab: string, repo: RepoType) {\n  const repoClassMap: Record<string, string> = {\n    inmemory: `InMemory${pascal}Repository`,\n    drizzle: `Drizzle${pascal}Repository`,\n    prisma: `Prisma${pascal}Repository`,\n  }\n  const repoFileMap: Record<string, string> = {\n    inmemory: `in-memory-${kebab}`,\n    drizzle: `drizzle-${kebab}`,\n    prisma: `prisma-${kebab}`,\n  }\n  return {\n    repoClass: repoClassMap[repo] ?? `${toPascalRepoType(repo)}${pascal}Repository`,\n    repoFile: repoFileMap[repo] ?? `${toKebabRepoType(repo)}-${kebab}`,\n  }\n}\n\n/** Resolve the style flag, defaulting to 'define' for new code. */\nfunction resolveStyle(style?: ModuleStyle): ModuleStyle {\n  return style ?? 'define'\n}\n\n/** DDD module index — nested folders, use-cases, domain services */\nexport function generateModuleIndex(ctx: TemplateContext & { repo: RepoType }): string {\n  const { pascal, kebab, plural = '', repo, style } = ctx\n  const { repoClass, repoFile } = repoMaps(pascal, kebab, repo)\n  const resolvedStyle = resolveStyle(style)\n\n  const header = `/**\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 (currently ${repoLabel(repo)})\n */`\n\n  const repoImports = `import { ${pascal.toUpperCase()}_REPOSITORY } from './domain/repositories/${kebab}.repository'\nimport { ${repoClass} } from './infrastructure/repositories/${repoFile}.repository'\nimport { ${pascal}Controller } from './presentation/${kebab}.controller'\n\n// Eagerly load decorated classes so @Controller()/@Service()/@Repository() decorators\n// register in the DI container. Recursive globs (./**/) so the module keeps working\n// however you nest files (e.g. moving controllers into a controllers/ sub-folder).\nimport.meta.glob(\n  [\n    './**/*.controller.ts',\n    './**/*.service.ts',\n    './**/*.repository.ts',\n    './application/use-cases/**/*.ts',\n    '!./**/*.test.ts',\n  ],\n  { eager: true },\n)`\n\n  const routesDoc = `    /**\n     * Declare HTTP routes for this module. Return value shape:\n     *\n     *   - \\`path\\`        — URL prefix for this route set, mounted under\n     *                     \\`/{apiPrefix}/v{version}{path}\\`.\n     *   - \\`controller\\`  — Controller class. Used both for the route\n     *                     handler bindings and OpenAPI spec generation.\n     *   - \\`version\\`     — Optional. Overrides the app-wide API version\n     *                     for this route set only.\n     *\n     * Return an **array** to mount multiple route sets under the\n     * same module (e.g. side-by-side v1 + v2 controllers):\n     *\n     *   return [\n     *     { path: '/${plural}', version: 1, controller: ${pascal}V1Controller },\n     *     { path: '/${plural}', version: 2, controller: ${pascal}V2Controller },\n     *   ]\n     */`\n\n  if (resolvedStyle === 'class') {\n    return `${header}\nimport { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'\n${repoImports}\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   * Currently wired to ${repoLabel(repo)}. To swap implementations, change the factory target.\n   */\n  register(container: Container): void {\n    container.registerFactory(${pascal.toUpperCase()}_REPOSITORY, () =>\n      container.resolve(${repoClass}),\n    )\n  }\n\n${routesDoc.replace(/^ {4}/gm, '  ').replace(/^ {6}/gm, '    ')}\n  routes(): ModuleRoutes {\n    return {\n      path: '/${plural}',\n      controller: ${pascal}Controller,\n    }\n  }\n}\n`\n  }\n\n  return `${header}\nimport { defineModule } from '@forinda/kickjs'\n${repoImports}\n\nexport const ${pascal}Module = defineModule({\n  name: '${pascal}Module',\n  build: () => ({\n    /**\n     * Register module dependencies in the DI container.\n     * Bind repository interface tokens to their implementations here.\n     * Currently wired to ${repoLabel(repo)}. To swap implementations, change the factory target.\n     */\n    register(container) {\n      container.registerFactory(${pascal.toUpperCase()}_REPOSITORY, () =>\n        container.resolve(${repoClass}),\n      )\n    },\n\n${routesDoc}\n    routes() {\n      return {\n        path: '/${plural}',\n        controller: ${pascal}Controller,\n      }\n    },\n  }),\n})\n`\n}\n\n/** REST module index — flat folder, service + controller, no use-cases */\nexport function generateRestModuleIndex(ctx: TemplateContext & { repo: RepoType }): string {\n  const { pascal, kebab, plural = '', repo, style } = ctx\n  const { repoClass, repoFile } = repoMaps(pascal, kebab, repo)\n  const resolvedStyle = resolveStyle(style)\n\n  const header = `/**\n * ${pascal} Module\n *\n * REST module with a flat folder structure.\n * Controller delegates to service, service wraps the repository.\n *\n * Structure:\n *   ${kebab}.controller.ts  — HTTP routes (CRUD)\n *   ${kebab}.service.ts     — Business logic\n *   ${kebab}.repository.ts  — Repository interface\n *   ${repoFile}.repository.ts — Repository implementation\n *   dtos/                   — Request/response schemas\n */`\n\n  const repoImports = `import { ${pascal.toUpperCase()}_REPOSITORY } from './${kebab}.repository'\nimport { ${repoClass} } from './${repoFile}.repository'\nimport { ${pascal}Controller } from './${kebab}.controller'\n\n// Eagerly load decorated classes so @Controller()/@Service()/@Repository() decorators\n// register in the DI container. Recursive globs (./**/) so the module keeps working\n// however you nest files (e.g. moving controllers into a controllers/ sub-folder).\nimport.meta.glob(\n  ['./**/*.controller.ts', './**/*.service.ts', './**/*.repository.ts', '!./**/*.test.ts'],\n  { eager: true },\n)`\n\n  const routesDoc = `    /**\n     * Declare HTTP routes for this module. Return value shape:\n     *\n     *   - \\`path\\`        — URL prefix for this route set.\n     *   - \\`controller\\`  — Controller class (also drives OpenAPI).\n     *   - \\`version\\`     — Optional. Overrides the app-wide API version.\n     *\n     * Return an **array** to mount multiple route sets — admin\n     * surfaces, side-by-side v1 + v2 controllers, etc:\n     *\n     *   return [\n     *     { path: '/${plural}', version: 1, controller: ${pascal}V1Controller },\n     *     { path: '/${plural}', version: 2, controller: ${pascal}V2Controller },\n     *   ]\n     */`\n\n  if (resolvedStyle === 'class') {\n    return `${header}\nimport { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'\n${repoImports}\n\nexport class ${pascal}Module implements AppModule {\n  register(container: Container): void {\n    container.registerFactory(${pascal.toUpperCase()}_REPOSITORY, () =>\n      container.resolve(${repoClass}),\n    )\n  }\n\n${routesDoc.replace(/^ {4}/gm, '  ').replace(/^ {6}/gm, '    ')}\n  routes(): ModuleRoutes {\n    return {\n      path: '/${plural}',\n      controller: ${pascal}Controller,\n    }\n  }\n}\n`\n  }\n\n  return `${header}\nimport { defineModule } from '@forinda/kickjs'\n${repoImports}\n\nexport const ${pascal}Module = defineModule({\n  name: '${pascal}Module',\n  build: () => ({\n    register(container) {\n      container.registerFactory(${pascal.toUpperCase()}_REPOSITORY, () =>\n        container.resolve(${repoClass}),\n      )\n    },\n\n${routesDoc}\n    routes() {\n      return {\n        path: '/${plural}',\n        controller: ${pascal}Controller,\n      }\n    },\n  }),\n})\n`\n}\n\n/** Minimal module index — just controller, no service/repo */\nexport function generateMinimalModuleIndex(ctx: TemplateContext): string {\n  const { pascal, kebab, plural = '', style } = ctx\n  const resolvedStyle = resolveStyle(style)\n\n  const routesDoc = `    /**\n     * Declare HTTP routes. Return value shape:\n     *\n     *   - \\`path\\`        — URL prefix for this route set.\n     *   - \\`controller\\`  — Controller class (also drives OpenAPI).\n     *   - \\`version\\`     — Optional. Overrides the app-wide API version.\n     *\n     * Return an array to mount multiple route sets:\n     *\n     *   return [\n     *     { path: '/${plural}', version: 1, controller: ${pascal}V1Controller },\n     *     { path: '/${plural}', version: 2, controller: ${pascal}V2Controller },\n     *   ]\n     */`\n\n  if (resolvedStyle === 'class') {\n    return `import { type AppModule, type ModuleRoutes } from '@forinda/kickjs'\nimport { ${pascal}Controller } from './${kebab}.controller'\n\nexport class ${pascal}Module implements AppModule {\n${routesDoc.replace(/^ {4}/gm, '  ').replace(/^ {6}/gm, '    ')}\n  routes(): ModuleRoutes {\n    return {\n      path: '/${plural}',\n      controller: ${pascal}Controller,\n    }\n  }\n}\n`\n  }\n\n  return `import { defineModule } from '@forinda/kickjs'\nimport { ${pascal}Controller } from './${kebab}.controller'\n\nexport const ${pascal}Module = defineModule({\n  name: '${pascal}Module',\n  build: () => ({\n${routesDoc}\n    routes() {\n      return {\n        path: '/${plural}',\n        controller: ${pascal}Controller,\n      }\n    },\n  }),\n})\n`\n}\n","import type { TemplateContext } from './types'\n\n/** DDD controller — injects use-cases, nested import paths */\nexport function generateController(ctx: TemplateContext): string {\n  const { pascal, kebab, plural = '', pluralPascal = '' } = ctx\n  return `import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'\nimport { ApiTags } from '@forinda/kickjs-swagger'\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'\nimport { ${pascal.toUpperCase()}_QUERY_CONFIG } from '../constants'\n\n// Each handler annotates its \\`ctx\\` with \\`Ctx<KickRoutes.${pascal}Controller['<method>']>\\`\n// so \\`ctx.params\\`, \\`ctx.body\\`, and \\`ctx.query\\` are typed end-to-end.\n// The \\`KickRoutes\\` namespace is generated by \\`kick typegen\\` (auto-run on\n// \\`kick dev\\`) — see https://kickjs.app/guide/typegen.\n\n@Controller()\nexport class ${pascal}Controller {\n  @Autowired() private readonly create${pascal}UseCase!: Create${pascal}UseCase\n  @Autowired() private readonly get${pascal}UseCase!: Get${pascal}UseCase\n  @Autowired() private readonly list${pluralPascal}UseCase!: List${pluralPascal}UseCase\n  @Autowired() private readonly update${pascal}UseCase!: Update${pascal}UseCase\n  @Autowired() private readonly delete${pascal}UseCase!: Delete${pascal}UseCase\n\n  @Get('/')\n  @ApiTags('${pascal}')\n  @ApiQueryParams(${pascal.toUpperCase()}_QUERY_CONFIG)\n  async list(ctx: Ctx<KickRoutes.${pascal}Controller['list']>) {\n    return ctx.paginate(\n      (parsed) => this.list${pluralPascal}UseCase.execute(parsed),\n      ${pascal.toUpperCase()}_QUERY_CONFIG,\n    )\n  }\n\n  @Get('/:id')\n  @ApiTags('${pascal}')\n  async getById(ctx: Ctx<KickRoutes.${pascal}Controller['getById']>) {\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  @Post('/', { body: create${pascal}Schema, name: 'Create${pascal}' })\n  @ApiTags('${pascal}')\n  async create(ctx: Ctx<KickRoutes.${pascal}Controller['create']>) {\n    const result = await this.create${pascal}UseCase.execute(ctx.body)\n    ctx.created(result)\n  }\n\n  @Put('/:id', { body: update${pascal}Schema, name: 'Update${pascal}' })\n  @ApiTags('${pascal}')\n  async update(ctx: Ctx<KickRoutes.${pascal}Controller['update']>) {\n    const result = await this.update${pascal}UseCase.execute(ctx.params.id, ctx.body)\n    ctx.json(result)\n  }\n\n  @Delete('/:id')\n  @ApiTags('${pascal}')\n  async remove(ctx: Ctx<KickRoutes.${pascal}Controller['remove']>) {\n    await this.delete${pascal}UseCase.execute(ctx.params.id)\n    ctx.noContent()\n  }\n}\n`\n}\n\n/** REST controller — injects service directly, flat import paths */\nexport function generateRestController(ctx: TemplateContext): string {\n  const { pascal, kebab } = ctx\n  const camel = pascal.charAt(0).toLowerCase() + pascal.slice(1)\n  return `import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'\nimport { ApiTags } from '@forinda/kickjs-swagger'\nimport { ${pascal}Service } from './${kebab}.service'\nimport { create${pascal}Schema } from './dtos/create-${kebab}.dto'\nimport { update${pascal}Schema } from './dtos/update-${kebab}.dto'\nimport { ${pascal.toUpperCase()}_QUERY_CONFIG } from './${kebab}.constants'\n\n// Each handler annotates its \\`ctx\\` with \\`Ctx<KickRoutes.${pascal}Controller['<method>']>\\`\n// so \\`ctx.params\\`, \\`ctx.body\\`, and \\`ctx.query\\` are typed end-to-end.\n// The \\`KickRoutes\\` namespace is generated by \\`kick typegen\\` (auto-run on\n// \\`kick dev\\`) — see https://kickjs.app/guide/typegen.\n\n@Controller()\nexport class ${pascal}Controller {\n  @Autowired() private readonly ${camel}Service!: ${pascal}Service\n\n  @Get('/')\n  @ApiTags('${pascal}')\n  @ApiQueryParams(${pascal.toUpperCase()}_QUERY_CONFIG)\n  async list(ctx: Ctx<KickRoutes.${pascal}Controller['list']>) {\n    return ctx.paginate(\n      (parsed) => this.${camel}Service.findPaginated(parsed),\n      ${pascal.toUpperCase()}_QUERY_CONFIG,\n    )\n  }\n\n  @Get('/:id')\n  @ApiTags('${pascal}')\n  async getById(ctx: Ctx<KickRoutes.${pascal}Controller['getById']>) {\n    const result = await this.${camel}Service.findById(ctx.params.id)\n    if (!result) return ctx.notFound('${pascal} not found')\n    ctx.json(result)\n  }\n\n  @Post('/', { body: create${pascal}Schema, name: 'Create${pascal}' })\n  @ApiTags('${pascal}')\n  async create(ctx: Ctx<KickRoutes.${pascal}Controller['create']>) {\n    const result = await this.${camel}Service.create(ctx.body)\n    ctx.created(result)\n  }\n\n  @Put('/:id', { body: update${pascal}Schema, name: 'Update${pascal}' })\n  @ApiTags('${pascal}')\n  async update(ctx: Ctx<KickRoutes.${pascal}Controller['update']>) {\n    const result = await this.${camel}Service.update(ctx.params.id, ctx.body)\n    ctx.json(result)\n  }\n\n  @Delete('/:id')\n  @ApiTags('${pascal}')\n  async remove(ctx: Ctx<KickRoutes.${pascal}Controller['remove']>) {\n    await this.${camel}Service.delete(ctx.params.id)\n    ctx.noContent()\n  }\n}\n`\n}\n","import type { TemplateContext } from './types'\n\nexport function generateCreateDTO(ctx: TemplateContext): string {\n  const { pascal } = ctx\n  return `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\nexport function generateUpdateDTO(ctx: TemplateContext): string {\n  const { pascal } = ctx\n  return `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\nexport function generateResponseDTO(ctx: TemplateContext): string {\n  const { pascal } = ctx\n  return `export interface ${pascal}ResponseDTO {\n  id: string\n  name: string\n  createdAt: string\n  updatedAt: string\n}\n`\n}\n","import type { TemplateContext } from './types'\n\nexport function generateRepositoryInterface(ctx: TemplateContext): string {\n  const { pascal, kebab, dtoPrefix = '../../application/dtos', tokenScope = 'app' } = ctx\n  return `/**\n * ${pascal} Repository Interface\n *\n * Defines the contract for data access.\n * The interface declares what operations are available;\n * implementations (in-memory, Drizzle, Prisma) fulfill the contract.\n *\n * To swap implementations, change the factory in the module's register() method.\n */\nimport { createToken } from '@forinda/kickjs'\nimport type { ${pascal}ResponseDTO } from '${dtoPrefix}/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '${dtoPrefix}/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '${dtoPrefix}/update-${kebab}.dto'\nimport type { ParsedQuery } from '@forinda/kickjs'\n\nexport interface I${pascal}Repository {\n  findById(id: string): Promise<${pascal}ResponseDTO | null>\n  findAll(): Promise<${pascal}ResponseDTO[]>\n  findPaginated(parsed: ParsedQuery): Promise<{ data: ${pascal}ResponseDTO[]; total: number }>\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\n/**\n * Collision-safe DI token bound to \\`I${pascal}Repository\\`.\n * \\`container.resolve(${pascal.toUpperCase()}_REPOSITORY)\\` and\n * \\`@Inject(${pascal.toUpperCase()}_REPOSITORY)\\` both return the typed\n * interface — no manual generic, no \\`any\\` cast.\n *\n * The \\`'${tokenScope}/'\\` prefix matches the project scope so\n * \\`kick-lint\\`'s \\`token-reserved-prefix\\` rule never fires —\n * adopters must NOT use the reserved \\`'kick/'\\` namespace.\n */\nexport const ${pascal.toUpperCase()}_REPOSITORY = createToken<I${pascal}Repository>('${tokenScope}/${pascal}/repository')\n`\n}\n\nexport function generateInMemoryRepository(ctx: TemplateContext): string {\n  const {\n    pascal,\n    kebab,\n    repoPrefix = '../../domain/repositories',\n    dtoPrefix = '../../application/dtos',\n  } = ctx\n  return `/**\n * In-Memory ${pascal} Repository\n *\n * 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'\nimport type { ParsedQuery } from '@forinda/kickjs'\nimport type { I${pascal}Repository } from '${repoPrefix}/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '${dtoPrefix}/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '${dtoPrefix}/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '${dtoPrefix}/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 findPaginated(parsed: ParsedQuery): Promise<{ data: ${pascal}ResponseDTO[]; total: number }> {\n    const all = Array.from(this.store.values())\n    const data = all.slice(parsed.pagination.offset, parsed.pagination.offset + parsed.pagination.limit)\n    return { data, total: all.length }\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      ...dto,\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\nexport function generateCustomRepository(ctx: TemplateContext): string {\n  const {\n    pascal,\n    kebab,\n    repoType = '',\n    repoPrefix = '../../domain/repositories',\n    dtoPrefix = '../../application/dtos',\n  } = ctx\n  const repoTypePascal =\n    repoType.charAt(0).toUpperCase() +\n    repoType.slice(1).replace(/-([a-z])/g, (_, c: string) => c.toUpperCase())\n  return `/**\n * ${repoTypePascal} ${pascal} Repository\n *\n * Stub implementation for a custom '${repoType}' repository.\n * Implements the repository interface using an in-memory Map as a placeholder.\n *\n * TODO: Replace the in-memory Map with your ${repoType} data-access logic.\n * See I${pascal}Repository for the interface contract.\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'\nimport type { ParsedQuery } from '@forinda/kickjs'\nimport type { I${pascal}Repository } from '${repoPrefix}/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '${dtoPrefix}/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '${dtoPrefix}/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '${dtoPrefix}/update-${kebab}.dto'\n\n@Repository()\nexport class ${repoTypePascal}${pascal}Repository implements I${pascal}Repository {\n  // TODO: Replace with your ${repoType} client/connection\n  private store = new Map<string, ${pascal}ResponseDTO>()\n\n  async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n    // TODO: Implement with ${repoType}\n    return this.store.get(id) ?? null\n  }\n\n  async findAll(): Promise<${pascal}ResponseDTO[]> {\n    // TODO: Implement with ${repoType}\n    return Array.from(this.store.values())\n  }\n\n  async findPaginated(parsed: ParsedQuery): Promise<{ data: ${pascal}ResponseDTO[]; total: number }> {\n    // TODO: Implement with ${repoType}\n    const all = Array.from(this.store.values())\n    const data = all.slice(parsed.pagination.offset, parsed.pagination.offset + parsed.pagination.limit)\n    return { data, total: all.length }\n  }\n\n  async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n    // TODO: Implement with ${repoType}\n    const now = new Date().toISOString()\n    const entity: ${pascal}ResponseDTO = {\n      id: randomUUID(),\n      ...dto,\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    // TODO: Implement with ${repoType}\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    // TODO: Implement with ${repoType}\n    if (!this.store.has(id)) throw HttpException.notFound('${pascal} not found')\n    this.store.delete(id)\n  }\n}\n`\n}\n","import type { TemplateContext } from './types'\n\nexport function generateControllerTest(ctx: TemplateContext): string {\n  const { pascal, kebab, plural = '' } = ctx\n  return `import { describe, it, expect, beforeEach } from 'vitest'\nimport { Container } from '@forinda/kickjs'\n\ndescribe('${pascal}Controller', () => {\n  beforeEach(() => {\n    Container.reset()\n  })\n\n  it('should be defined', () => {\n    expect(true).toBe(true)\n  })\n\n  describe('POST /${plural}', () => {\n    it('should create a new ${kebab}', async () => {\n      // TODO: Set up test module, call create endpoint, assert 201\n      expect(true).toBe(true)\n    })\n  })\n\n  describe('GET /${plural}', () => {\n    it('should return paginated ${plural}', async () => {\n      // TODO: Set up test module, call list endpoint, assert { data, meta }\n      expect(true).toBe(true)\n    })\n  })\n\n  describe('GET /${plural}/:id', () => {\n    it('should return a ${kebab} by id', async () => {\n      // TODO: Create a ${kebab}, then fetch by id, assert match\n      expect(true).toBe(true)\n    })\n\n    it('should return 404 for non-existent ${kebab}', async () => {\n      // TODO: Fetch non-existent id, assert 404\n      expect(true).toBe(true)\n    })\n  })\n\n  describe('PUT /${plural}/:id', () => {\n    it('should update an existing ${kebab}', async () => {\n      // TODO: Create, update, assert changes\n      expect(true).toBe(true)\n    })\n  })\n\n  describe('DELETE /${plural}/:id', () => {\n    it('should delete a ${kebab}', async () => {\n      // TODO: Create, delete, assert gone\n      expect(true).toBe(true)\n    })\n  })\n})\n`\n}\n\nexport function generateRepositoryTest(ctx: TemplateContext): string {\n  const {\n    pascal,\n    kebab,\n    plural = '',\n    repoPrefix = `../infrastructure/repositories/in-memory-${kebab}.repository`,\n  } = ctx\n  return `import { describe, it, expect, beforeEach } from 'vitest'\nimport { InMemory${pascal}Repository } from '${repoPrefix}'\n\ndescribe('InMemory${pascal}Repository', () => {\n  let repo: InMemory${pascal}Repository\n\n  beforeEach(() => {\n    repo = new InMemory${pascal}Repository()\n  })\n\n  it('should create and retrieve a ${kebab}', async () => {\n    const created = await repo.create({ name: 'Test ${pascal}' })\n    expect(created).toBeDefined()\n    expect(created.name).toBe('Test ${pascal}')\n    expect(created.id).toBeDefined()\n\n    const found = await repo.findById(created.id)\n    expect(found).toEqual(created)\n  })\n\n  it('should return null for non-existent id', async () => {\n    const found = await repo.findById('non-existent')\n    expect(found).toBeNull()\n  })\n\n  it('should list all ${plural}', async () => {\n    await repo.create({ name: '${pascal} 1' })\n    await repo.create({ name: '${pascal} 2' })\n\n    const all = await repo.findAll()\n    expect(all).toHaveLength(2)\n  })\n\n  it('should return paginated results', async () => {\n    await repo.create({ name: '${pascal} 1' })\n    await repo.create({ name: '${pascal} 2' })\n    await repo.create({ name: '${pascal} 3' })\n\n    const result = await repo.findPaginated({\n      filters: [],\n      sort: [],\n      search: '',\n      pagination: { page: 1, limit: 2, offset: 0 },\n    })\n\n    expect(result.data).toHaveLength(2)\n    expect(result.total).toBe(3)\n  })\n\n  it('should update a ${kebab}', async () => {\n    const created = await repo.create({ name: 'Original' })\n    const updated = await repo.update(created.id, { name: 'Updated' })\n    expect(updated.name).toBe('Updated')\n  })\n\n  it('should delete a ${kebab}', async () => {\n    const created = await repo.create({ name: 'To Delete' })\n    await repo.delete(created.id)\n    const found = await repo.findById(created.id)\n    expect(found).toBeNull()\n  })\n})\n`\n}\n","import type { TemplateContext } from './types'\n\n/** REST service — wraps repository with CRUD methods, replaces use-cases for flat pattern */\nexport function generateRestService(ctx: TemplateContext): string {\n  const { pascal, kebab } = ctx\n  return `import { Service, Inject, HttpException } from '@forinda/kickjs'\nimport type { ParsedQuery } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from './${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from './dtos/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from './dtos/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from './dtos/update-${kebab}.dto'\n\n@Service()\nexport class ${pascal}Service {\n  constructor(\n    @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n  ) {}\n\n  async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n    return this.repo.findById(id)\n  }\n\n  async findAll(): Promise<${pascal}ResponseDTO[]> {\n    return this.repo.findAll()\n  }\n\n  async findPaginated(parsed: ParsedQuery) {\n    return this.repo.findPaginated(parsed)\n  }\n\n  async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n    return this.repo.create(dto)\n  }\n\n  async update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n    return this.repo.update(id, dto)\n  }\n\n  async delete(id: string): Promise<void> {\n    await this.repo.delete(id)\n  }\n}\n`\n}\n\n/** REST constants — query config for flat pattern */\nexport function generateRestConstants(ctx: TemplateContext): string {\n  const { pascal } = ctx\n  return `import type { QueryFieldConfig } from '@forinda/kickjs'\n\nexport const ${pascal.toUpperCase()}_QUERY_CONFIG: QueryFieldConfig = {\n  filterable: ['name'],\n  sortable: ['name', 'createdAt'],\n  searchable: ['name'],\n}\n`\n}\n","type ProjectTemplate = 'rest' | 'minimal'\nexport type ProjectRuntime = 'express' | 'fastify' | 'h3'\n\n/** Per-runtime import source + factory name for the scaffolded `runtime:` option. */\nconst RUNTIME_FACTORY: Record<ProjectRuntime, { from: string; name: string }> = {\n  express: { from: '@forinda/kickjs', name: 'expressRuntime' },\n  fastify: { from: '@forinda/kickjs/fastify', name: 'fastifyRuntime' },\n  h3: { from: '@forinda/kickjs/h3', name: 'h3Runtime' },\n}\n\n/**\n * Generate src/index.ts entry file with template-specific bootstrap.\n *\n * The runtime is always emitted explicitly (`runtime: expressRuntime()` etc.)\n * so the entry file is self-documenting and switching engines is a one-line\n * edit. Fastify / h3 parse bodies natively, so the REST template skips the\n * `express.json()` middleware (and the `express` import) under those engines.\n *\n * All templates export the app for the Vite plugin (dev mode).\n */\nexport function generateEntryFile(\n  name: string,\n  template: ProjectTemplate,\n  version: string,\n  packages: string[] = [],\n  runtime: ProjectRuntime = 'express',\n): string {\n  const factory = RUNTIME_FACTORY[runtime]\n  const isExpress = runtime === 'express'\n\n  switch (template) {\n    case 'minimal': {\n      const imports: string[] = []\n      const adapters: string[] = []\n\n      // The runtime factory comes from the core package for Express, or a\n      // subpath for Fastify / h3.\n      const kickImport = isExpress\n        ? `import { bootstrap, ${factory.name} } from '@forinda/kickjs'`\n        : `import { bootstrap } from '@forinda/kickjs'\\nimport { ${factory.name} } from '${factory.from}'`\n\n      if (packages.includes('swagger')) {\n        imports.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`)\n        adapters.push(`    SwaggerAdapter({ info: { title: '${name}', version: '${version}' } }),`)\n      }\n      if (packages.includes('devtools')) {\n        imports.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`)\n        adapters.push(`    DevToolsAdapter(),`)\n      }\n      const importsBlock = imports.length ? imports.join('\\n') + '\\n' : ''\n      const adaptersBlock = adapters.length ? `,\\n  adapters: [\\n${adapters.join('\\n')}\\n  ]` : ''\n\n      return `import 'reflect-metadata'\n// Side-effect import — registers the extended env schema with kickjs\n// **before** any controller / service / @Value gets resolved. Without\n// this line ConfigService.get('YOUR_KEY') returns undefined because the\n// cached schema would still be the base shape. See guide/configuration.\nimport './config'\n${kickImport}\n${importsBlock}import { modules } from './modules'\n\n// Export the app for the Vite plugin (dev mode)\nexport const app = await bootstrap({ modules, runtime: ${factory.name}()${adaptersBlock} })\n`\n    }\n\n    case 'rest':\n    default: {\n      // Build adapters based on user-selected packages\n      const restImports: string[] = []\n      const restAdapters: string[] = []\n\n      if (packages.includes('devtools')) {\n        restImports.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`)\n        restAdapters.push(`    DevToolsAdapter(),`)\n      }\n      if (packages.includes('swagger')) {\n        restImports.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`)\n        restAdapters.push(\n          `    SwaggerAdapter({\\n      info: { title: '${name}', version: '${version}' },\\n    }),`,\n        )\n      }\n      const restImportsBlock = restImports.length ? restImports.join('\\n') + '\\n' : ''\n      const restAdaptersBlock = restAdapters.length\n        ? `\\n  adapters: [\\n${restAdapters.join('\\n')}\\n  ],`\n        : ''\n\n      // Express needs `express.json()` for body parsing; Fastify / h3 parse\n      // bodies natively, so adding it would consume the body stream twice.\n      const kickNamed = ['bootstrap', 'requestId', 'requestLogger', 'helmet', 'cors']\n      if (isExpress) kickNamed.push(factory.name)\n      const kickImport = isExpress\n        ? `import express from 'express'\\nimport {\\n  ${kickNamed.join(',\\n  ')},\\n} from '@forinda/kickjs'`\n        : `import {\\n  ${kickNamed.join(',\\n  ')},\\n} from '@forinda/kickjs'\\nimport { ${factory.name} } from '${factory.from}'`\n      const bodyParserLine = isExpress ? `\\n    express.json(),` : ''\n\n      return `import 'reflect-metadata'\n// Side-effect import — registers the extended env schema with kickjs\n// **before** any controller / service / @Value gets resolved. Without\n// this line ConfigService.get('YOUR_KEY') returns undefined because the\n// cached schema would still be the base shape. See guide/configuration.\nimport './config'\n${kickImport}\n${restImportsBlock}import { modules } from './modules'\n\n// Export the app for the Vite plugin (dev mode)\nexport const app = await bootstrap({\n  modules,\n  runtime: ${factory.name}(),${restAdaptersBlock}\n  middleware: [\n    helmet(),\n    cors({ origin: '*' }),\n    requestId(),\n    requestLogger(),${bodyParserLine}\n  ],\n})\n`\n    }\n  }\n}\n\n/** Generate src/modules/index.ts module registry */\nexport function generateModulesIndex(): string {\n  return `import { defineModules } from '@forinda/kickjs'\nimport { HelloModule } from './hello/hello.module'\n\n// Remove HelloModule and run: kick g module <name>\n// \\`defineModules()\\` returns a chainable list — \\`kick g module\\` appends\n// \\`.mount(NewModule())\\` to the chain on every generation.\nexport const modules = defineModules().mount(HelloModule())\n`\n}\n\n/**\n * Generate `src/config/index.ts` — the project's typed env schema.\n *\n * Default-exports a `defineEnv(...)` schema so `kick typegen` can\n * infer it into the global `KickEnv` registry, and *also* calls\n * `loadEnv(envSchema)` as a module-load side effect so `ConfigService`\n * and `@Value()` see the extended shape from the very first DI\n * resolution. The companion `src/index.ts` template adds\n * `import './config'` immediately after `reflect-metadata` so the\n * registration runs before `bootstrap()` constructs anything.\n *\n * After typegen runs:\n *\n *   @Value('DATABASE_URL') private url!: Env<'DATABASE_URL'>\n *   process.env.DATABASE_URL  // typed as string\n *\n * Both autocomplete and type-check at compile time.\n */\nexport function generateEnvFile(schemaLib: 'zod' | 'valibot' | 'yup' = 'zod'): string {\n  if (schemaLib === 'valibot') {\n    return `import { loadEnvFromSchema } from '@forinda/kickjs/config'\nimport { fromValibot } from '@forinda/kickjs-schema/valibot'\nimport * as v from 'valibot'\n\n/**\n * Project environment schema (Valibot).\n *\n * \\`fromValibot\\` wraps the Valibot schema as a \\`KickSchema\\` so the\n * env loader, validate middleware, and swagger spec generator all see\n * the same shape. The default export is the contract \\`kick typegen\\`\n * reads to populate \\`KickEnv\\` via \\`InferSchemaOutput<typeof _envSchema>\\`\n * — that's what makes \\`@Value('FOO')\\` autocomplete and\n * \\`process.env.FOO\\` typed.\n *\n * @example\n *   DATABASE_URL: v.pipe(v.string(), v.url()),\n *   JWT_SECRET:   v.pipe(v.string(), v.minLength(32)),\n *   REDIS_URL:    v.optional(v.pipe(v.string(), v.url())),\n */\nconst envSchema = fromValibot(\n  v.object({\n    PORT: v.optional(v.pipe(v.string(), v.transform(Number)), '3000'),\n    NODE_ENV: v.optional(v.picklist(['development', 'production', 'test']), 'development'),\n    LOG_LEVEL: v.optional(v.string(), 'info'),\n    // DATABASE_URL: v.pipe(v.string(), v.url()),\n  }),\n)\n\n/**\n * IMPORTANT — side effect: register the schema with kickjs's env cache\n * **at module-load time**. \\`ConfigService\\` and \\`@Value()\\` both consume\n * this cache, and they will fall back to the base schema (or undefined)\n * if no extended schema has been registered before they're resolved.\n *\n * As long as \\`src/index.ts\\` imports this file (\\`import './config'\\`) at\n * the top — before \\`bootstrap()\\` runs — every controller and service\n * in the app sees the typed extended values.\n */\nexport const env = loadEnvFromSchema(envSchema)\n\nexport default envSchema\n`\n  }\n\n  if (schemaLib === 'yup') {\n    return `import { loadEnvFromSchema } from '@forinda/kickjs/config'\nimport { fromYup } from '@forinda/kickjs-schema/yup'\nimport * as yup from 'yup'\n\n/**\n * Project environment schema (Yup).\n *\n * \\`fromYup\\` wraps the Yup schema as a \\`KickSchema\\` so the env loader,\n * validate middleware, and swagger spec generator all see the same\n * shape. The default export is the contract \\`kick typegen\\` reads to\n * populate \\`KickEnv\\` via \\`InferSchemaOutput<typeof _envSchema>\\`.\n *\n * Note: Yup's \\`.url()\\` defaults to http/https; database connection\n * strings like \\`postgres://\\` use \\`.matches(/^[a-z]+:\\\\/\\\\/.+/i)\\` or\n * a plain \\`.string().required()\\`.\n *\n * @example\n *   DATABASE_URL: yup.string().required(),\n *   JWT_SECRET:   yup.string().min(32).required(),\n *   REDIS_URL:    yup.string().url().optional(),\n */\nconst envSchema = fromYup(\n  yup.object({\n    PORT: yup.number().default(3000),\n    NODE_ENV: yup\n      .string()\n      .oneOf(['development', 'production', 'test'])\n      .default('development'),\n    LOG_LEVEL: yup.string().default('info'),\n    // DATABASE_URL: yup.string().required(),\n  }),\n)\n\n/**\n * IMPORTANT — side effect: register the schema with kickjs's env cache\n * **at module-load time**. \\`ConfigService\\` and \\`@Value()\\` both consume\n * this cache, and they will fall back to the base schema (or undefined)\n * if no extended schema has been registered before they're resolved.\n *\n * As long as \\`src/index.ts\\` imports this file (\\`import './config'\\`) at\n * the top — before \\`bootstrap()\\` runs — every controller and service\n * in the app sees the typed extended values.\n */\nexport const env = loadEnvFromSchema(envSchema)\n\nexport default envSchema\n`\n  }\n\n  // zod (default)\n  return `import { loadEnvFromSchema } from '@forinda/kickjs/config'\nimport { fromZod } from '@forinda/kickjs-schema/zod'\nimport { z } from 'zod'\n\n/**\n * Project environment schema (Zod).\n *\n * \\`fromZod\\` wraps the Zod schema as a \\`KickSchema\\` so the env loader,\n * validate middleware, and swagger spec generator all see the same\n * shape. The default export is the contract \\`kick typegen\\` reads to\n * populate \\`KickEnv\\` via \\`InferSchemaOutput<typeof _envSchema>\\` —\n * that's what makes \\`@Value('FOO')\\` autocomplete and\n * \\`process.env.FOO\\` typed.\n *\n * @example\n *   DATABASE_URL: z.string().url(),\n *   JWT_SECRET: z.string().min(32),\n *   REDIS_URL: z.string().url().optional(),\n */\nconst envSchema = fromZod(\n  z.object({\n    PORT: z.coerce.number().default(3000),\n    NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),\n    LOG_LEVEL: z.string().default('info'),\n    // DATABASE_URL: z.string().url(),\n  }),\n)\n\n/**\n * IMPORTANT — side effect: register the schema with kickjs's env cache\n * **at module-load time**. \\`ConfigService\\` and \\`@Value()\\` both consume\n * this cache, and they will fall back to the base schema (or undefined)\n * if no extended schema has been registered before they're resolved.\n *\n * As long as \\`src/index.ts\\` imports this file (\\`import './config'\\`) at\n * the top — before \\`bootstrap()\\` runs — every controller and service\n * in the app sees the typed extended values.\n */\nexport const env = loadEnvFromSchema(envSchema)\n\nexport default envSchema\n`\n}\n\n/** Generate src/modules/hello/hello.service.ts */\nexport function generateHelloService(): string {\n  return `import { Service } from '@forinda/kickjs'\n\n@Service()\nexport class HelloService {\n  greet(name: string) {\n    return { message: \\`Hello \\${name} from KickJS!\\`, timestamp: new Date().toISOString() }\n  }\n\n  healthCheck() {\n    return { status: 'ok', uptime: process.uptime() }\n  }\n}\n`\n}\n\n/** Generate src/modules/hello/hello.controller.ts */\nexport function generateHelloController(): string {\n  return `import { Controller, Get, Autowired, type Ctx } from '@forinda/kickjs'\nimport { HelloService } from './hello.service'\n\n// \\`Ctx<KickRoutes.HelloController['<method>']>\\` is generated by\n// \\`kick typegen\\` (auto-run on \\`kick dev\\`). The first run after a fresh\n// scaffold creates \\`.kickjs/types/routes.ts\\` so this file typechecks.\n// See https://kickjs.app/guide/typegen.\n\n@Controller()\nexport class HelloController {\n  @Autowired() private readonly helloService!: HelloService\n\n  @Get('/')\n  index(ctx: Ctx<KickRoutes.HelloController['index']>) {\n    ctx.json(this.helloService.greet('World'))\n  }\n\n  @Get('/health')\n  health(ctx: Ctx<KickRoutes.HelloController['health']>) {\n    ctx.json(this.helloService.healthCheck())\n  }\n}\n`\n}\n\n/** Generate src/modules/hello/hello.module.ts */\nexport function generateHelloModule(): string {\n  return `import { defineModule } from '@forinda/kickjs'\nimport { HelloController } from './hello.controller'\n\nexport const HelloModule = defineModule({\n  name: 'HelloModule',\n  build: () => ({\n    // \\`register(container)\\` is optional — only implement it when you need\n    // to bind a token to a concrete implementation, e.g.\n    //   register(container) {\n    //     container.registerFactory(USER_REPOSITORY, () => container.resolve(InMemoryUserRepository))\n    //   }\n    // The HelloService uses @Service() so the decorator handles registration.\n\n    routes() {\n      return {\n        path: '/hello',\n        controller: HelloController,\n      }\n    },\n  }),\n})\n`\n}\n\n/** Generate kick.config.ts CLI configuration */\nexport function generateKickConfig(\n  template: ProjectTemplate,\n  defaultRepo: string = 'inmemory',\n  packageManager: 'pnpm' | 'npm' | 'yarn' | 'bun' = 'pnpm',\n  runtime: 'express' | 'fastify' | 'h3' = 'express',\n): string {\n  // `inmemory` is the only built-in; every other name (incl. the\n  // deprecated prisma/drizzle) is emitted as a `{ name }` custom repo.\n  const repoValue = defaultRepo === 'inmemory' ? `'inmemory'` : `{ name: '${defaultRepo}' }`\n\n  return `import { defineConfig } from '@forinda/kickjs-cli'\n\nexport default defineConfig({\n  pattern: '${template}',\n  // The HTTP engine this app boots on (matches \\`bootstrap({ runtime })\\` in\n  // src/index.ts). Dep-aware commands read it: \\`kick add upload\\` installs the\n  // engine's multipart driver, \\`kick doctor\\` checks the engine peers, and\n  // \\`kick typegen\\` flips the runtime escape-hatch types to this engine.\n  runtime: '${runtime}',\n  // Pinned so \\`kick add\\` and other dep-installing commands always use the\n  // project's intended package manager, regardless of which lockfile exists.\n  packageManager: '${packageManager}',\n  modules: {\n    dir: 'src/modules',\n    repo: ${repoValue},\n    pluralize: true,\n  },\n\n  // \\`kick typegen\\` populates \\`.kickjs/types/\\` so \\`Ctx<KickRoutes.X['method']>\\`\n  // resolves to fully-typed params/body/query. Auto-runs on \\`kick dev\\`.\n  // \\`'kickjs-schema'\\` routes inference through \\`InferSchemaOutput\\` so the\n  // typegen works for any wrapped schema (Zod / Valibot / Yup). Switch\n  // to \\`'zod'\\` if you ship Zod schemas without \\`fromZod()\\` wrapping, or\n  // set \\`schemaValidator: false\\` to skip schema-driven body typing.\n  typegen: {\n    schemaValidator: 'kickjs-schema',\n  },\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: 'ci:check',\n      description: 'Run typecheck + format check',\n      steps: ['npx tsc --noEmit', 'npx prettier --check src/'],\n      aliases: ['verify'],\n    },\n  ],\n})\n`\n}\n","import type { ModuleContext } from './types'\nimport { generateMinimalModuleIndex } from '../templates'\n\nexport async function generateMinimalFiles(ctx: ModuleContext): Promise<void> {\n  const { pascal, kebab, plural, style, write } = ctx\n\n  // Module file (named `<kebab>.module.ts` so Vite's module-discovery plugin picks it up)\n  await write(`${kebab}.module.ts`, generateMinimalModuleIndex({ pascal, kebab, plural, style }))\n\n  await write(\n    `${kebab}.controller.ts`,\n    `import { Controller, Get, type Ctx } from '@forinda/kickjs'\n\n// \\`Ctx<KickRoutes.${pascal}Controller['<method>']>\\` is generated by\n// \\`kick typegen\\` (auto-run on \\`kick dev\\`).\n\n@Controller()\nexport class ${pascal}Controller {\n  @Get('/')\n  async list(ctx: Ctx<KickRoutes.${pascal}Controller['list']>) {\n    ctx.json({ message: '${pascal} list' })\n  }\n}\n`,\n  )\n}\n","import type { ModuleContext } from './types'\nimport { toKebabCase } from '../../utils/naming'\nimport {\n  generateRestModuleIndex,\n  generateRestController,\n  generateRestConstants,\n  generateRestService,\n  generateCreateDTO,\n  generateUpdateDTO,\n  generateResponseDTO,\n  generateRepositoryInterface,\n  generateInMemoryRepository,\n  generateCustomRepository,\n  generateControllerTest,\n  generateRepositoryTest,\n} from '../templates'\n\nexport async function generateRestFiles(ctx: ModuleContext): Promise<void> {\n  const { pascal, kebab, plural, pluralPascal, repo, noTests, tokenScope, style, write } = ctx\n\n  // Module file (named `<kebab>.module.ts` so Vite's module-discovery plugin picks it up)\n  await write(`${kebab}.module.ts`, generateRestModuleIndex({ pascal, kebab, plural, repo, style }))\n\n  // Constants\n  await write(`${kebab}.constants.ts`, generateRestConstants({ pascal, kebab }))\n\n  // Controller (injects service)\n  await write(\n    `${kebab}.controller.ts`,\n    generateRestController({ pascal, kebab, plural, pluralPascal }),\n  )\n\n  // Service (wraps repository)\n  await write(`${kebab}.service.ts`, generateRestService({ pascal, kebab }))\n\n  // DTOs\n  await write(`dtos/create-${kebab}.dto.ts`, generateCreateDTO({ pascal, kebab }))\n  await write(`dtos/update-${kebab}.dto.ts`, generateUpdateDTO({ pascal, kebab }))\n  await write(`dtos/${kebab}-response.dto.ts`, generateResponseDTO({ pascal, kebab }))\n\n  // Repository interface (flat imports)\n  await write(\n    `${kebab}.repository.ts`,\n    generateRepositoryInterface({ pascal, kebab, dtoPrefix: './dtos', tokenScope }),\n  )\n\n  // Repository implementation (flat imports). `inmemory` is the only\n  // built-in (zero-dep working impl); every other name scaffolds a\n  // generic custom stub — prisma/drizzle no longer have dedicated\n  // generators (see `warnIfDeprecatedRepo`).\n  const isInMemory = repo === 'inmemory'\n  const repoFile = isInMemory ? `in-memory-${kebab}` : `${toKebabCase(repo)}-${kebab}`\n  const repoContent = isInMemory\n    ? generateInMemoryRepository({ pascal, kebab, repoPrefix: '.', dtoPrefix: './dtos' })\n    : generateCustomRepository({\n        pascal,\n        kebab,\n        repoType: repo,\n        repoPrefix: '.',\n        dtoPrefix: './dtos',\n      })\n  await write(`${repoFile}.repository.ts`, repoContent)\n\n  // Tests\n  if (!noTests) {\n    // Always generate an in-memory repo for testing — even when using drizzle/prisma\n    if (repo !== 'inmemory') {\n      await write(\n        `in-memory-${kebab}.repository.ts`,\n        generateInMemoryRepository({ pascal, kebab, repoPrefix: '.', dtoPrefix: './dtos' }),\n      )\n    }\n    await write(\n      `__tests__/${kebab}.controller.test.ts`,\n      generateControllerTest({ pascal, kebab, plural }),\n    )\n    await write(\n      `__tests__/${kebab}.repository.test.ts`,\n      generateRepositoryTest({\n        pascal,\n        kebab,\n        plural,\n        repoPrefix: `../in-memory-${kebab}.repository`,\n      }),\n    )\n  }\n}\n","import { join } from 'node:path'\nimport { writeFileSafe, fileExists } from '../utils/fs'\nimport { confirm, log } from '../utils/prompts'\nimport { colors } from '../utils/colors'\nimport { toPascalCase, toKebabCase, pluralize, pluralizePascal } from '../utils/naming'\nimport { escapeRegex } from '../utils/regex'\nimport { readFile, writeFile } from 'node:fs/promises'\nimport type { ProjectPattern, RepoTypeConfig } from '../config'\nimport type { ModuleStyle } from './templates/types'\nimport { generateMinimalFiles, generateRestFiles } from './patterns'\nimport type { ModuleContext } from './patterns'\n\nexport type BuiltinRepoType = 'inmemory'\nexport type RepoType = BuiltinRepoType | (string & {})\n\n/** Resolve a RepoTypeConfig (from kick.config.ts) into a flat repo type string */\nexport function resolveRepoType(config?: RepoTypeConfig): RepoType {\n  if (!config) return 'inmemory'\n  if (typeof config === 'string') return config\n  return config.name\n}\n\ninterface GenerateModuleOptions {\n  name: string\n  modulesDir: string\n  noEntity?: boolean\n  noTests?: boolean\n  repo?: RepoType\n  minimal?: boolean\n  force?: boolean\n  pattern?: ProjectPattern\n  dryRun?: boolean\n  /** When false, skip pluralization — use singular names for folders, routes, and classes */\n  pluralize?: boolean\n  /** Prisma client import path (default: '@prisma/client', Prisma 7+: '@/generated/prisma/client') */\n  prismaClientPath?: string\n  /**\n   * DI-token scope prefix substituted into emitted `createToken<T>()`\n   * literals. Resolved by the orchestrating command from\n   * `kick.config.ts > tokenScope` or the project's package.json.\n   * Falls back to `'app'` when not set so the generator can be called\n   * without a config in tests/fixtures.\n   */\n  tokenScope?: string\n  /**\n   * Module declaration style — `'define'` (factory, default) or\n   * `'class'` (legacy). Resolved by the orchestrating command from\n   * `kick.config.ts > modules.style`.\n   */\n  style?: ModuleStyle\n}\n\n/**\n * Generate a module — structure depends on the project pattern.\n *\n * Patterns:\n *   rest         — flat folder: controller + service + DTOs + repo (default)\n *   minimal      — just controller + module index\n */\nexport async function generateModule(options: GenerateModuleOptions): Promise<string[]> {\n  const { name, modulesDir, noEntity, noTests, repo = 'inmemory', force, dryRun } = options\n  const shouldPluralize = options.pluralize !== false\n\n  let pattern = options.pattern ?? 'rest'\n  if (options.minimal) pattern = 'minimal'\n\n  const kebab = toKebabCase(name)\n  const pascal = toPascalCase(name)\n  const plural = shouldPluralize ? pluralize(kebab) : kebab\n  const pluralPascal = shouldPluralize ? pluralizePascal(pascal) : pascal\n  const moduleDir = join(modulesDir, plural)\n\n  const files: string[] = []\n  let overwriteAll = force ?? false\n\n  const write = async (relativePath: string, content: string) => {\n    const fullPath = join(moduleDir, relativePath)\n    if (dryRun) {\n      files.push(fullPath)\n      return\n    }\n    if (!overwriteAll && (await fileExists(fullPath))) {\n      const shouldOverwrite = await confirm({\n        message: `File exists: ${colors.dim(relativePath)}. Overwrite?`,\n        initialValue: false,\n      })\n      if (!shouldOverwrite) {\n        log.warn(`Skipped: ${relativePath}`)\n        return\n      }\n    }\n    await writeFileSafe(fullPath, content)\n    files.push(fullPath)\n  }\n\n  const ctx: ModuleContext = {\n    kebab,\n    pascal,\n    plural,\n    pluralPascal,\n    moduleDir,\n    repo,\n    noEntity: noEntity ?? false,\n    noTests: noTests ?? false,\n    prismaClientPath: options.prismaClientPath ?? '@prisma/client',\n    tokenScope: options.tokenScope ?? 'app',\n    style: options.style ?? 'define',\n    write,\n    files,\n  }\n\n  switch (pattern) {\n    case 'minimal':\n      await generateMinimalFiles(ctx)\n      break\n    case 'rest':\n    default:\n      await generateRestFiles(ctx)\n      break\n  }\n\n  // Auto-register in modules index (all patterns need this)\n  if (!dryRun) {\n    await autoRegisterModule(modulesDir, pascal, plural, kebab, ctx.style)\n  }\n\n  return files\n}\n\n// ── Auto-register in modules index ──────────────────────────────────────\n\n/**\n * Add a new module to `src/modules/index.ts`. Handles both the\n * fresh-project initial-write path (creates the file with the right\n * shape for the resolved style) and the established-project append\n * path (inserts the import + extends the flat array OR fluent chain\n * via {@link appendModuleEntry}).\n *\n * Exported so `scaffold.ts` can reuse it — both call sites had\n * line-for-line identical bodies before consolidation, including\n * the inline-regex chain-append bug CodeRabbit caught on PR #196.\n * Single source of truth here keeps the orchestrator and scaffold\n * paths from drifting again.\n */\nexport async function autoRegisterModule(\n  modulesDir: string,\n  pascal: string,\n  plural: string,\n  kebab: string,\n  style: ModuleStyle = 'define',\n): Promise<void> {\n  const indexPath = join(modulesDir, 'index.ts')\n  const exists = await fileExists(indexPath)\n  const importPath = `./${plural}/${kebab}.module`\n  // `defineModule` factories are called at the registration site\n  // (`${pascal}Module()`); legacy class modules are passed by reference\n  // (`${pascal}Module`). Application's loader discriminates class vs\n  // instance at boot, so both forms work — `style` only controls what\n  // the orchestrator emits.\n  const entryToken = style === 'class' ? `${pascal}Module` : `${pascal}Module()`\n\n  if (!exists) {\n    // For 'class' style we emit the legacy flat-array form because\n    // `defineModules` is the factory-form companion. For 'define' (default)\n    // we emit the fluent `defineModules().mount(...)` chain so subsequent\n    // `kick g module` invocations append cleanly.\n    const initialBody =\n      style === 'class'\n        ? `import type { AppModuleEntry } from '@forinda/kickjs'\nimport { ${pascal}Module } from '${importPath}'\n\nexport const modules: AppModuleEntry[] = [${entryToken}]\n`\n        : `import { defineModules } from '@forinda/kickjs'\nimport { ${pascal}Module } from '${importPath}'\n\nexport const modules = defineModules().mount(${entryToken})\n`\n    await writeFileSafe(indexPath, initialBody)\n    return\n  }\n\n  let content = await readFile(indexPath, 'utf-8')\n\n  // Two independent checks — a stale comment, a doc snippet, or a\n  // partially-edited file shouldn't make the gate skip both halves.\n  //\n  //   1. Import-line check: look for an exact `import { XModule }\n  //      from '<importPath>'` statement, not just any `XModule`\n  //      mention. A comment that names XModule doesn't satisfy this.\n  //   2. Registry-entry check: look for `XModule` (word-bounded)\n  //      inside the actual `export const modules` initializer rhs,\n  //      not anywhere in the file. Recovers a half-edited registry\n  //      where the import survived but the .mount entry was deleted.\n  const importLine = `import { ${pascal}Module } from '${importPath}'`\n  const escapedImportPath = escapeRegex(importPath)\n  const importPresentRe = new RegExp(\n    `^import\\\\s*\\\\{[^}]*\\\\b${escapeRegex(pascal)}Module\\\\b[^}]*\\\\}\\\\s*from\\\\s*['\"]${escapedImportPath}['\"]`,\n    'm',\n  )\n  if (!importPresentRe.test(content)) {\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\n  // Independently confirm the registry rhs already names this entry\n  // before skipping the append. Scoped to the `export const modules`\n  // slice via `findModulesRhsSpan` so an `XModule` mention in an\n  // unrelated builder above the registry doesn't mask a missing\n  // `.mount(XModule())` further down.\n  const span = findModulesRhsSpan(content)\n  if (span) {\n    const rhsSlice = content.slice(span.rhsStart, span.rhsEnd + 1)\n    const entryPresentRe = new RegExp(`\\\\b${escapeRegex(pascal)}Module\\\\b`)\n    if (!entryPresentRe.test(rhsSlice)) {\n      content = appendModuleEntry(content, entryToken)\n    }\n  } else {\n    // No recognizable registry shape — fall back to the previous\n    // best-effort behaviour: try appending; appendModuleEntry returns\n    // content unchanged when it can't find a target.\n    content = appendModuleEntry(content, entryToken)\n  }\n\n  await writeFile(indexPath, content, 'utf-8')\n}\n\n/**\n * Append `entryToken` (e.g. `LionModule()` or bare `LionModule`) to\n * the project's modules registry. Handles two shapes:\n *\n *   1. Flat array literal:\n *      `export const modules: AppModuleEntry[] = [HelloModule()]`\n *   2. Fluent factory chain:\n *      `export const modules = defineModules().mount(HelloModule())`\n *\n * If neither shape is detected, content is returned unchanged — the\n * adopter's registration site is non-standard and they mount the\n * new module themselves.\n *\n * Exported so `scaffold.ts`'s auto-register can reuse the same\n * balanced-paren scanner — duplicating the regex caused\n * `mount(UserModule())` to corrupt on the scaffold path before this\n * was hoisted out.\n */\nexport function appendModuleEntry(content: string, entryToken: string): string {\n  const span = findModulesRhsSpan(content)\n  if (!span) return content\n\n  // Shape 1 — flat array literal at the rhs.\n  if (span.shape === 'array') {\n    const inside = content.slice(span.rhsStart + 1, span.rhsEnd)\n    const trimmed = inside.trim()\n    let rewritten: string\n    if (!trimmed) {\n      rewritten = `[${entryToken}]`\n    } else {\n      const needsComma = trimmed.endsWith(',') ? '' : ','\n      rewritten = `[${inside.trimEnd()}${needsComma} ${entryToken}]`\n    }\n    return content.slice(0, span.rhsStart) + rewritten + content.slice(span.rhsEnd + 1)\n  }\n\n  // Shape 2 — `defineModules()` fluent chain at the rhs. Insert\n  // `.mount(...)` right at `chainEnd` (the offset just past the\n  // last `.mount(...)`'s closing `)` or just past `defineModules()`'s\n  // closing `)` when the chain is empty).\n  return `${content.slice(0, span.chainEnd)}\\n  .mount(${entryToken})${content.slice(span.chainEnd)}`\n}\n\n/**\n * Span returned by {@link findModulesRhsSpan}. Both shapes carry the\n * `rhsStart` (the offset of `[` for arrays or `d` for the chain) and\n * an `end` offset describing where the rhs concludes:\n *\n *   - `array`: `rhsEnd` points at the matching `]` (inclusive).\n *   - `chain`: `chainEnd` points just past the last `.mount(...)`\n *      call (or just past `defineModules()`'s closing `)` when the\n *      chain is empty). For consistency with arrays, `rhsEnd =\n *      chainEnd - 1` so a `[rhsStart, rhsEnd + 1)` slice covers the\n *      whole initializer.\n */\ntype ModulesRhsSpan =\n  | { shape: 'array'; rhsStart: number; rhsEnd: number }\n  | { shape: 'chain'; rhsStart: number; rhsEnd: number; chainEnd: number }\n\n/**\n * Locate the `export const modules = <rhs>` initializer in `content`\n * and return the rhs's start/end offsets along with which shape it\n * is (flat array vs `defineModules()` chain). Used by both the\n * append path (`appendModuleEntry`) AND the remove path\n * (`stripChainMount` / array-entry rm regex) so neither mutates\n * unrelated text elsewhere in the file.\n *\n * Returns `null` when no `export const modules` declaration is\n * found, or when its rhs doesn't match either supported shape.\n */\nexport function findModulesRhsSpan(content: string): ModulesRhsSpan | null {\n  const declMatch = /export\\s+const\\s+modules\\b[^=]*=/.exec(content)\n  if (!declMatch) return null\n  const eqEnd = declMatch.index + declMatch[0].length\n  let rhsStart = eqEnd\n  while (rhsStart < content.length && /\\s/.test(content[rhsStart] ?? '')) rhsStart++\n\n  if (content[rhsStart] === '[') {\n    const close = balancedBracketClose(content, rhsStart)\n    if (close === -1) return null\n    return { shape: 'array', rhsStart, rhsEnd: close }\n  }\n\n  if (content.slice(rhsStart, rhsStart + 'defineModules'.length) === 'defineModules') {\n    const chainEnd = findChainEnd(content, rhsStart)\n    if (chainEnd === -1) return null\n    return { shape: 'chain', rhsStart, rhsEnd: chainEnd - 1, chainEnd }\n  }\n\n  return null\n}\n\n/**\n * Locate the insertion point after the last `.mount(...)` call in a\n * `defineModules()...` chain, or after `defineModules()` itself when\n * the chain is empty. Returns the source-string offset to insert at,\n * or -1 when the chain isn't found.\n *\n * The scanner walks balanced parens so nested factory calls inside\n * `.mount(X())` don't break boundary detection.\n */\nfunction findChainEnd(src: string, fromIdx = 0): number {\n  // Match the CALL site, not the import statement. We require an\n  // immediately-following `(` (allowing whitespace) to anchor on\n  // `defineModules(...)` and skip past `import { defineModules }`.\n  // `fromIdx` lets the caller scope the search to the rhs of an\n  // `export const modules =` declaration so unrelated calls\n  // elsewhere in the file aren't matched.\n  const callRegex = /defineModules\\s*\\(/g\n  callRegex.lastIndex = fromIdx\n  const match = callRegex.exec(src)\n  if (!match) return -1\n  // `match.index` points at `d`; `(` is at `match.index + match[0].length - 1`.\n  let i = match.index + match[0].length - 1\n  if (src[i] !== '(') return -1\n  // Balance the args of `defineModules(...)`.\n  i = balancedClose(src, i)\n  if (i === -1) return -1\n  i++\n  // Now consume zero or more `.mount(...)` calls. After each, `i`\n  // points just past its closing `)` so the next iteration sees a\n  // potential `.mount(...)` ahead.\n  for (;;) {\n    let j = i\n    while (j < src.length && /\\s/.test(src[j] ?? '')) j++\n    if (src[j] !== '.') break\n    if (src.slice(j, j + 6) !== '.mount') break\n    j += 6\n    while (j < src.length && /\\s/.test(src[j] ?? '')) j++\n    if (src[j] !== '(') break\n    const close = balancedClose(src, j)\n    if (close === -1) break\n    i = close + 1\n  }\n  return i\n}\n\n/**\n * Skip past a `//` line comment or `/* … *\\/` block comment that\n * starts at offset `i`. Returns the offset of the first character\n * after the comment, or `i` unchanged when there's no comment at\n * that position. Used by the balanced-paren / bracket scanners so\n * a `]` or `)` inside a comment doesn't terminate the scan early.\n */\nfunction skipComment(src: string, i: number): number {\n  const two = src.slice(i, i + 2)\n  if (two === '//') {\n    i += 2\n    while (i < src.length && src[i] !== '\\n') i++\n    return i\n  }\n  if (two === '/*') {\n    i += 2\n    while (i + 1 < src.length && !(src[i] === '*' && src[i + 1] === '/')) i++\n    return i + 2\n  }\n  return i\n}\n\n/**\n * Given an offset pointing at `[`, return the offset of its matching\n * `]`. Skips brackets inside string literals so `['weird]name']`\n * doesn't break, and inside `//` / `/* *\\/` comments. Returns -1 on\n * imbalance.\n */\nfunction balancedBracketClose(src: string, openIdx: number): number {\n  if (src[openIdx] !== '[') return -1\n  let depth = 1\n  let i = openIdx + 1\n  while (i < src.length) {\n    const next = src.slice(i, i + 2)\n    if (next === '//' || next === '/*') {\n      i = skipComment(src, i)\n      continue\n    }\n    const ch = src[i] ?? ''\n    if (ch === \"'\" || ch === '\"' || ch === '`') {\n      const quote = ch\n      i++\n      while (i < src.length && src[i] !== quote) {\n        if (src[i] === '\\\\') i++\n        i++\n      }\n      if (i < src.length) i++\n      continue\n    }\n    if (ch === '[') depth++\n    else if (ch === ']') {\n      depth--\n      if (depth === 0) return i\n    }\n    i++\n  }\n  return -1\n}\n\n/**\n * Given an offset pointing at `(`, return the offset of its matching\n * `)`, or -1 on imbalance. Skips parens inside string literals\n * (single, double, backtick) and inside `//` / `/* *\\/` comments —\n * a `)` in either would terminate the scan early and corrupt the\n * insertion offset.\n */\nfunction balancedClose(src: string, openIdx: number): number {\n  if (src[openIdx] !== '(') return -1\n  let depth = 1\n  let i = openIdx + 1\n  while (i < src.length) {\n    const next = src.slice(i, i + 2)\n    if (next === '//' || next === '/*') {\n      i = skipComment(src, i)\n      continue\n    }\n    const ch = src[i] ?? ''\n    if (ch === \"'\" || ch === '\"' || ch === '`') {\n      // Skip string literal — find matching unescaped quote.\n      const quote = ch\n      i++\n      while (i < src.length && src[i] !== quote) {\n        if (src[i] === '\\\\') i++\n        i++\n      }\n      if (i < src.length) i++\n      continue\n    }\n    if (ch === '(') depth++\n    else if (ch === ')') {\n      depth--\n      if (depth === 0) return i\n    }\n    i++\n  }\n  return -1\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\n/**\n * Scaffold a `defineAdapter()` factory under `src/adapters/<name>.adapter.ts`.\n *\n * v4 dropped the `class implements AppAdapter` pattern in favour of the\n * `defineAdapter()` factory (architecture.md §21.3.4). The generated\n * template uses the new factory shape so adopters get a working\n * adapter with all four lifecycle hooks (beforeMount, beforeStart,\n * afterStart, shutdown), a typed config object with defaults, and the\n * factory's call / `.scoped()` / `.async()` surfaces — without\n * writing a single class.\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 {\n  defineAdapter,\n  type AdapterContext,\n  type AdapterMiddleware,\n  type ContributorRegistrations,\n  type Constructor,\n} from '@forinda/kickjs'\n\n/**\n * Configuration for the ${pascal} adapter.\n *\n * Adapters typically take a small config object so callers can tune\n * behaviour at bootstrap time. Keep the shape narrow — anything\n * derived from the environment should be read inside the build\n * function via getEnv(), not forced onto the caller.\n */\nexport interface ${pascal}AdapterConfig {\n  // Add your adapter configuration here, e.g.:\n  // enabled?: boolean\n  // apiKey?: string\n}\n\n/**\n * ${pascal} adapter — built via \\`defineAdapter()\\` so callers get the\n * factory's call / \\`.scoped()\\` / \\`.async()\\` surfaces for free.\n *\n * Hooks into the Application lifecycle to add middleware, routes,\n * Context Contributors, or external service connections.\n *\n * Every lifecycle hook below is OPTIONAL. The scaffold emits all of\n * them so adopters can browse what's available and delete what they\n * don't need — \\`build()\\` returning \\`{}\\` is also valid for an adapter\n * that only contributes config defaults.\n *\n * @example\n * \\`\\`\\`ts\n * import { bootstrap } from '@forinda/kickjs'\n * import { ${pascal}Adapter } from './adapters/${kebab}.adapter'\n *\n * bootstrap({\n *   modules,\n *   adapters: [${pascal}Adapter({ /* config overrides *\\\\/ })],\n * })\n * \\`\\`\\`\n */\nexport const ${pascal}Adapter = defineAdapter<${pascal}AdapterConfig>({\n  name: '${pascal}Adapter',\n  defaults: {\n    // Default config values go here. The adopter's overrides shallow-merge\n    // on top of these before \\`build()\\` runs.\n  },\n  build: (_config, { name: _name }) => {\n    // Closures inside \\`build()\\` are how each adapter instance owns its\n    // own state (database client, Map, timer handle, …). The same\n    // \\`_config\\` is visible to every hook below.\n\n    return {\n      /**\n       * Express middleware entries the Application mounts at named phases.\n       *\n       * \\`phase\\` controls where each handler sits in the pipeline:\n       *   'beforeGlobal' | 'afterGlobal' | 'beforeRoutes' | 'afterRoutes'.\n       *\n       * \\`path\\` (optional) scopes the entry to a path prefix.\n       *\n       * Delete this hook entirely if you don't add middleware.\n       */\n      middleware(): AdapterMiddleware[] {\n        return [\n          // Example: add a custom header to all responses\n          // {\n          //   phase: 'beforeGlobal',\n          //   handler: (_req, res, next) => {\n          //     res.setHeader('X-${pascal}', 'true')\n          //     next()\n          //   },\n          // },\n          // Example: scope a rate limiter to one path prefix\n          // {\n          //   phase: 'beforeRoutes',\n          //   path: '/api/v1/auth',\n          //   handler: rateLimit({ max: 10 }),\n          // },\n        ]\n      },\n\n      /**\n       * Runs BEFORE global middleware. Mount routes that should bypass the\n       * middleware stack — health checks, docs UI, static assets, OAuth\n       * callbacks. Anything you want reachable even if a global middleware\n       * later in the chain rejects requests.\n       *\n       * Delete this hook if you have no early routes.\n       */\n      beforeMount(_ctx: AdapterContext): void {\n        // Example:\n        // _ctx.app.get('/${kebab}/status', (_req, res) => res.json({ status: 'ok' }))\n      },\n\n      /**\n       * Fires once per controller class as the router mounts. Use this to\n       * collect route metadata for OpenAPI specs, dependency graphs, route\n       * inventories, devtools dashboards.\n       *\n       * Delete this hook unless your adapter introspects the route registry.\n       */\n      onRouteMount(_controllerClass: Constructor, _mountPath: string): void {\n        // Example (Swagger-style): collect routes for the spec.\n        // openApiSpec.addController(_controllerClass, _mountPath)\n      },\n\n      /**\n       * Runs AFTER modules + routes are wired, BEFORE the server starts.\n       * Right place for late-stage DI registrations or final config validation.\n       *\n       * Delete this hook if there's nothing to wire post-modules.\n       */\n      beforeStart(_ctx: AdapterContext): void {\n        // Example: _ctx.container.registerInstance(MY_TOKEN, new MyService(_config))\n      },\n\n      /**\n       * Runs AFTER the HTTP server is listening. The raw \\`http.Server\\` is\n       * available on \\`ctx.server\\` — attach upgrade handlers (Socket.IO,\n       * gRPC, GraphQL subscriptions), warm caches, log a banner.\n       *\n       * Delete this hook if you don't need the running server reference.\n       */\n      afterStart(_ctx: AdapterContext): void {\n        // Example: const io = new Server(_ctx.server)\n      },\n\n      /**\n       * Returns Context Contributors to merge into every route's pipeline\n       * at the \\`'adapter'\\` precedence level. Per-route handlers can\n       * override the value at the method / class / module level.\n       *\n       * Delete this hook unless your adapter ships typed per-request values\n       * (auth user, tenant, locale, feature flags, geo, etc).\n       */\n      contributors(): ContributorRegistrations {\n        return [\n          // Example:\n          // import { defineHttpContextDecorator } from '@forinda/kickjs'\n          // declare module '@forinda/kickjs' { interface ContextMeta { ${kebab}: { id: string } } }\n          // const Load${pascal} = defineHttpContextDecorator({\n          //   key: '${kebab}',\n          //   resolve: (ctx) => ({ id: ctx.req.headers['x-${kebab}-id'] as string }),\n          // })\n          // return [Load${pascal}.registration]\n        ]\n      },\n\n      /**\n       * Runs on graceful shutdown (SIGINT/SIGTERM). Clean up long-lived\n       * resources the adapter owns: close connections, flush buffers,\n       * cancel timers. The framework runs every adapter's \\`shutdown\\`\n       * concurrently via \\`Promise.allSettled\\` — one failure won't block\n       * sibling adapters.\n       *\n       * Delete this hook if your adapter holds no resources.\n       */\n      async shutdown(): Promise<void> {\n        // Example: await this.pool.end()\n        // Example: clearInterval(this.heartbeatTimer)\n      },\n    }\n  },\n})\n`,\n  )\n  files.push(filePath)\n\n  return files\n}\n","import { resolve, join } from 'node:path'\nimport { pluralize, toKebabCase } from './naming'\nimport type { ProjectPattern } from '../config'\n\n/**\n * Flat folder mapping — the layout for both `rest` and `minimal`.\n * Files live at the module root or in shallow subdirectories.\n */\nconst FLAT_FOLDER_MAP: Record<string, string> = {\n  controller: '',\n  service: '',\n  dto: 'dtos',\n  guard: 'guards',\n  middleware: 'middleware',\n  contributor: 'contributors',\n}\n\nexport interface ResolveOutDirOptions {\n  /** The artifact type (controller, service, dto, guard, middleware) */\n  type: string\n  /** Explicit -o / --out dir from CLI flag (takes highest priority) */\n  outDir?: string\n  /** Module name from --module flag */\n  moduleName?: string\n  /** Modules directory (from config or default) */\n  modulesDir?: string\n  /** Standalone default directory when no --module is used (e.g. 'src/controllers') */\n  defaultDir: string\n  /** Project pattern — determines folder structure inside modules */\n  pattern?: ProjectPattern\n  /** Whether to pluralize the module folder name (default: true) */\n  shouldPluralize?: boolean\n}\n\n/**\n * Resolve the output directory for a generator artifact.\n *\n * Priority:\n *   1. Explicit --out flag (always wins)\n *   2. --module flag → maps into module's folder (DDD or flat based on pattern)\n *   3. Standalone default directory\n */\nexport function resolveOutDir(options: ResolveOutDirOptions): string {\n  const {\n    type,\n    outDir,\n    moduleName,\n    modulesDir = 'src/modules',\n    defaultDir,\n    shouldPluralize = true,\n  } = options\n\n  // Explicit --out always wins\n  if (outDir) return resolve(outDir)\n\n  // Module-scoped: place inside the module's folder. All patterns\n  // (rest/minimal) share the flat folder layout.\n  if (moduleName) {\n    const folderMap = FLAT_FOLDER_MAP\n    const kebab = toKebabCase(moduleName)\n    const folder = shouldPluralize ? pluralize(kebab) : kebab\n    const subfolder = folderMap[type] ?? ''\n    const base = join(modulesDir, folder)\n    return resolve(subfolder ? join(base, subfolder) : base)\n  }\n\n  // Standalone default\n  return resolve(defaultDir)\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\nimport { resolveOutDir } from '../utils/resolve-out-dir'\nimport type { ProjectPattern } from '../config'\n\ninterface GenerateMiddlewareOptions {\n  name: string\n  outDir?: string\n  moduleName?: string\n  modulesDir?: string\n  pattern?: ProjectPattern\n  pluralize?: boolean\n}\n\nexport async function generateMiddleware(options: GenerateMiddlewareOptions): Promise<string[]> {\n  const { name, moduleName, modulesDir, pattern } = options\n  const outDir = resolveOutDir({\n    type: 'middleware',\n    outDir: options.outDir,\n    moduleName,\n    modulesDir,\n    defaultDir: 'src/middleware',\n    pattern,\n    shouldPluralize: options.pluralize ?? true,\n  })\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. The factory below closes over the\n  // resolved options object; pass them at the call site —\n  // \\`${camel}({ foo: 'bar' })\\` — and the closure preserves them across\n  // every request.\n}\n\n/**\n * ${toPascalCase(name)} middleware.\n *\n * Usage in bootstrap (fires on every request):\n *   middleware: [${camel}()]\n *\n * Usage with adapter — phase controls *when* the handler runs:\n *\n *   middleware() {\n *     return [{ handler: ${camel}(), phase: 'afterGlobal' }]\n *   }\n *\n * Phase semantics (see \\`MiddlewarePhase\\` JSDoc for the full contract):\n *   - 'beforeGlobal' / 'afterGlobal' / 'beforeRoutes' — fire on every\n *     request, before module routes run.\n *   - 'afterRoutes' — fires ONLY when no route matched (404 fall-through)\n *     OR a route handler called \\`next()\\` without ending the response.\n *     Controllers that call \\`ctx.json(…)\\` end the chain and skip this\n *     phase. For per-response work (logging, metrics) attach to\n *     \\`res.on('finish', …)\\` from an earlier-phase middleware instead.\n *\n * Optional path scope — string, RegExp, or array of either:\n *   middleware() {\n *     return [{\n *       handler: ${camel}({ region: 'eu' }),\n *       phase: 'afterGlobal',\n *       path: ['/api', /^\\\\/admin/],\n *     }]\n *   }\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. \\`options\\` is captured by\n    // closure — log or read it anywhere in this handler body.\n    void options\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'\nimport { resolveOutDir } from '../utils/resolve-out-dir'\nimport type { ProjectPattern } from '../config'\n\ninterface GenerateGuardOptions {\n  name: string\n  outDir?: string\n  moduleName?: string\n  modulesDir?: string\n  pattern?: ProjectPattern\n  pluralize?: boolean\n}\n\nexport async function generateGuard(options: GenerateGuardOptions): Promise<string[]> {\n  const { name, moduleName, modulesDir, pattern } = options\n  const outDir = resolveOutDir({\n    type: 'guard',\n    outDir: options.outDir,\n    moduleName,\n    modulesDir,\n    defaultDir: 'src/guards',\n    pattern,\n    shouldPluralize: options.pluralize ?? true,\n  })\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'\nimport type { RequestContext } from '@forinda/kickjs'\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'\nimport { resolveOutDir } from '../utils/resolve-out-dir'\nimport type { ProjectPattern } from '../config'\n\ninterface GenerateServiceOptions {\n  name: string\n  outDir?: string\n  moduleName?: string\n  modulesDir?: string\n  pattern?: ProjectPattern\n  pluralize?: boolean\n}\n\nexport async function generateService(options: GenerateServiceOptions): Promise<string[]> {\n  const { name, moduleName, modulesDir, pattern } = options\n  const outDir = resolveOutDir({\n    type: 'service',\n    outDir: options.outDir,\n    moduleName,\n    modulesDir,\n    defaultDir: 'src/services',\n    pattern,\n    shouldPluralize: options.pluralize ?? true,\n  })\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'\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'\nimport { resolveOutDir } from '../utils/resolve-out-dir'\nimport type { ProjectPattern } from '../config'\n\ninterface GenerateControllerOptions {\n  name: string\n  outDir?: string\n  moduleName?: string\n  modulesDir?: string\n  pattern?: ProjectPattern\n  pluralize?: boolean\n}\n\nexport async function generateController(options: GenerateControllerOptions): Promise<string[]> {\n  const { name, moduleName, modulesDir, pattern } = options\n  const outDir = resolveOutDir({\n    type: 'controller',\n    outDir: options.outDir,\n    moduleName,\n    modulesDir,\n    defaultDir: 'src/controllers',\n    pattern,\n    shouldPluralize: options.pluralize ?? true,\n  })\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, type Ctx } from '@forinda/kickjs'\n\n// \\`Ctx<KickRoutes.${pascal}Controller['<method>']>\\` is generated by\n// \\`kick typegen\\` (auto-run on \\`kick dev\\`). After the first run, your IDE\n// will autocomplete \\`ctx.params\\`, \\`ctx.body\\`, and \\`ctx.query\\`.\n// See https://kickjs.app/guide/typegen for details.\n\n@Controller()\nexport class ${pascal}Controller {\n  // @Autowired() private readonly myService!: MyService\n\n  @Get('/')\n  async list(ctx: Ctx<KickRoutes.${pascal}Controller['list']>) {\n    ctx.json({ message: '${pascal} list' })\n  }\n\n  @Post('/')\n  async create(ctx: Ctx<KickRoutes.${pascal}Controller['create']>) {\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'\nimport { resolveOutDir } from '../utils/resolve-out-dir'\nimport type { ProjectPattern } from '../config'\n\ninterface GenerateDtoOptions {\n  name: string\n  outDir?: string\n  moduleName?: string\n  modulesDir?: string\n  pattern?: ProjectPattern\n  pluralize?: boolean\n}\n\nexport async function generateDto(options: GenerateDtoOptions): Promise<string[]> {\n  const { name, moduleName, modulesDir, pattern } = options\n  const outDir = resolveOutDir({\n    type: 'dto',\n    outDir: options.outDir,\n    moduleName,\n    modulesDir,\n    defaultDir: 'src/dtos',\n    pattern,\n    shouldPluralize: options.pluralize ?? true,\n  })\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","type ProjectTemplate = 'rest' | 'minimal'\n\n/**\n * Supported schema libraries — passed through to `fromZod` /\n * `fromValibot` / `fromYup` in the generated env file. `zod` is the\n * default for `--yes` because it has the deepest ecosystem\n * compatibility (OpenAPI generation, Standard Schema brand for\n * `kick typegen`).\n */\nexport type SchemaLib = 'zod' | 'valibot' | 'yup'\n\n/** Map of optional package names to their npm package identifiers */\nconst PACKAGE_DEPS: Record<string, string> = {\n  swagger: '@forinda/kickjs-swagger',\n  ws: '@forinda/kickjs-ws',\n  queue: '@forinda/kickjs-queue',\n  devtools: '@forinda/kickjs-devtools',\n}\n\n/** Schema-lib runtime dependency ranges. Pinned to a recent release. */\nconst SCHEMA_LIB_DEPS: Record<SchemaLib, { name: string; range: string }> = {\n  zod: { name: 'zod', range: '^4.3.6' },\n  valibot: { name: 'valibot', range: '^1.4.1' },\n  yup: { name: 'yup', range: '^1.7.1' },\n}\n\n/**\n * Map of package name → semver range string (`^x.y.z`). Resolved\n * from `npm view <name> version` upstream so per-package independent\n * versioning is honoured at scaffold time. Every sibling\n * `@forinda/kickjs-*` package we might add to the new project must\n * appear here; missing keys throw during package.json generation\n * (loud failure beats silently shipping `^undefined`).\n */\nexport type SiblingVersions = Record<string, string>\n\nfunction take(versions: SiblingVersions, name: string): string {\n  const v = versions[name]\n  if (!v) {\n    throw new Error(\n      `generatePackageJson: missing resolved version for ${name}. ` +\n        `Add it to SIBLING_PACKAGES in generators/project.ts.`,\n    )\n  }\n  return v\n}\n\n/** Generate package.json with template-aware dependencies */\nexport function generatePackageJson(\n  name: string,\n  template: ProjectTemplate,\n  versions: SiblingVersions,\n  packages: string[] = [],\n  schemaLib: SchemaLib = 'zod',\n  runtime: 'express' | 'fastify' | 'h3' = 'express',\n): string {\n  const schemaDep = SCHEMA_LIB_DEPS[schemaLib]\n  const baseDeps: Record<string, string> = {\n    '@forinda/kickjs': take(versions, '@forinda/kickjs'),\n    // The schema-agnostic abstraction kickjs-schema wraps zod / valibot\n    // / yup behind a single `KickSchema` interface — env validation,\n    // body validation, and swagger spec generation all flow through\n    // `detectSchema()`. Shipping it as a direct dep (rather than a peer)\n    // keeps the new-project install one-step.\n    '@forinda/kickjs-schema': take(versions, '@forinda/kickjs-schema'),\n    // `dotenv` is an optional peer of @forinda/kickjs — scaffolded apps\n    // get it pre-installed so `.env` files Just Work. Apps that load\n    // env from the shell or a secret manager can drop this safely.\n    dotenv: '^17.3.1',\n    'reflect-metadata': '^0.2.2',\n    [schemaDep.name]: schemaDep.range,\n  }\n\n  // Engine peers for the chosen runtime (optional peers of @forinda/kickjs).\n  if (runtime === 'express') {\n    // Express is the engine itself.\n    baseDeps.express = '^5.1.0'\n  } else if (runtime === 'fastify') {\n    baseDeps.fastify = '^5.0.0'\n    baseDeps['@fastify/middie'] = '^9.0.0'\n    // Static serving uses `serve-static` (no express dependency).\n    baseDeps['serve-static'] = '^2.2.0'\n  } else if (runtime === 'h3') {\n    baseDeps.h3 = '^1.0.0'\n    baseDeps['serve-static'] = '^2.2.0'\n  }\n\n  // Add user-selected optional packages — each looked up against\n  // the resolved version map so they're independently up-to-date.\n  for (const pkg of packages) {\n    const dep = PACKAGE_DEPS[pkg]\n    if (dep && !baseDeps[dep]) {\n      baseDeps[dep] = take(versions, dep)\n    }\n  }\n\n  return JSON.stringify(\n    {\n      name,\n      // Project starts at 0.0.0 — adopters bump as they ship. Tying\n      // the project version to the CLI version (the previous\n      // behaviour) made every scaffolded app `5.4.0` on day one,\n      // which broke npm publishing for adopters trying their first\n      // release.\n      version: '0.0.0',\n      type: 'module',\n      scripts: {\n        // `kick dev` (not bare `vite`): it boots Vite itself AND owns the\n        // typegen-on-save watcher. Plain `vite` gives working HMR but\n        // frozen `.kickjs/types` — new routes silently lose their typing\n        // until a manual `kick typegen`.\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        typegen: 'kick typegen',\n        lint: 'eslint src/',\n        format: 'prettier --write src/',\n      },\n      dependencies: baseDeps,\n      devDependencies: {\n        '@forinda/kickjs-cli': take(versions, '@forinda/kickjs-cli'),\n        '@forinda/kickjs-vite': take(versions, '@forinda/kickjs-vite'),\n        '@swc/core': '^1.15.21',\n        // Express types only when Express is the engine (it's the only runtime\n        // that imports `express` in src/index.ts).\n        ...(runtime === 'express' ? { '@types/express': '^5.0.6' } : {}),\n        '@types/node': '^25.0.0',\n        'unplugin-swc': '^1.5.9',\n        vite: '^8.0.3',\n        vitest: '^4.1.2',\n        typescript: '^6.0.3',\n        prettier: '^3.8.1',\n      },\n    },\n    null,\n    2,\n  )\n}\n\n/**\n * Generate vite.config.ts with the KickJS Vite plugin.\n *\n * The plugin handles:\n * - SSR environment setup for backend Node.js code\n * - Virtual module generation (virtual:kickjs/app)\n * - Module auto-discovery (scans *.module.ts files)\n * - HMR with selective container invalidation\n * - Express mounting via configureServer() post-hook\n * - httpServer piping to adapters (WsAdapter, Socket.IO, etc.)\n */\nexport function generateViteConfig(): string {\n  return `import { defineConfig } from 'vite'\nimport { resolve } from 'node:path'\nimport swc from 'unplugin-swc'\nimport { kickjsVitePlugin, envWatchPlugin } from '@forinda/kickjs-vite'\n\nexport default defineConfig({\n  oxc: false,\n  plugins: [\n    swc.vite(),\n    kickjsVitePlugin({ entry: 'src/index.ts' }),\n    // Watches .env files and triggers a full reload on change so the\n    // dev server picks up env tweaks without a manual restart.\n    envWatchPlugin(),\n  ],\n  resolve: {\n    alias: {\n      '@': resolve(__dirname, 'src'),\n    },\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/** Generate tsconfig.json with decorator support */\nexport function generateTsConfig(): string {\n  return JSON.stringify(\n    {\n      compilerOptions: {\n        target: 'ES2022',\n        module: 'ESNext',\n        moduleResolution: 'bundler',\n        lib: ['ES2022'],\n        types: ['node', 'vite/client'],\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 omitted so .kickjs/types/*.d.ts can sit outside src/\n        paths: { '@/*': ['./src/*'] },\n      },\n      // .kickjs/types is generated by `kick typegen` and refreshed\n      // automatically on `kick dev`. Including it here makes\n      // `container.resolve()` and module discovery type-safe.\n      // Both .d.ts and .ts are matched: registry/services/modules are\n      // declarations, but routes.ts holds resolvable imports from your\n      // controllers' Zod schemas (TS silently degrades inline `import('...')`\n      // inside `.d.ts` files under `moduleResolution: 'bundler'`).\n      include: ['src', '.kickjs/types/**/*.d.ts', '.kickjs/types/**/*.ts'],\n    },\n    null,\n    2,\n  )\n}\n\n/** Generate .prettierrc with project formatting rules */\nexport function generatePrettierConfig(): string {\n  return 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/** Generate .editorconfig for consistent editor settings */\nexport function generateEditorConfig(): string {\n  return `# https://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n`\n}\n\n/** Generate .gitignore with common Node.js patterns */\nexport function generateGitIgnore(): string {\n  return `node_modules/\ndist/\n.env\ncoverage/\n.DS_Store\n*.tsbuildinfo\n.kickjs/\n`\n}\n\n/** Generate .gitattributes for consistent line endings */\nexport function generateGitAttributes(): string {\n  return `# Auto-detect text files and normalise line endings to LF\n* text=auto eol=lf\n\n# Explicitly mark generated / binary files\n*.png binary\n*.jpg binary\n*.jpeg binary\n*.gif binary\n*.ico binary\n*.woff binary\n*.woff2 binary\n*.ttf binary\n*.eot binary\n\n# Lock files — treat as generated\npnpm-lock.yaml -diff linguist-generated\nyarn.lock -diff linguist-generated\npackage-lock.json -diff linguist-generated\n`\n}\n\n/** Generate .env file with default environment variables */\nexport function generateEnv(): string {\n  return `PORT=3000\nNODE_ENV=development\n`\n}\n\n/** Generate .env.example file as a template */\nexport function generateEnvExample(): string {\n  return `PORT=3000\nNODE_ENV=development\n`\n}\n\n/** Generate vitest.config.ts for test configuration */\nexport function generateVitestConfig(): string {\n  return `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","import { execSync } from 'node:child_process'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport type { Command } from 'commander'\nimport { loadKickConfig, PACKAGE_MANAGERS, type PackageManager } from '../config'\n\ninterface PackageEntry {\n  pkg: string\n  peers: string[]\n  description: string\n  dev?: boolean\n  /**\n   * `true` for packages every project needs (framework + Vite plugin +\n   * CLI). `kick new` installs these regardless of options chosen, and\n   * future package-removal flows refuse to drop them.\n   */\n  core?: boolean\n  /**\n   * Set when the package still installs but should no longer be the\n   * default choice. The string is the migration hint shown both in\n   * `kick add --list --all` and as a warning when the package is added.\n   */\n  deprecated?: string\n}\n\n/** Registry of KickJS packages and their required peer dependencies */\nexport const PACKAGE_REGISTRY: Record<string, PackageEntry> = {\n  // Core (always installed by kick new — required for the framework to run)\n  kickjs: {\n    pkg: '@forinda/kickjs',\n    peers: ['express'],\n    description: 'Unified framework: DI, decorators, routing, middleware',\n    core: true,\n  },\n  vite: {\n    pkg: '@forinda/kickjs-vite',\n    peers: ['vite'],\n    description: 'Vite plugin: dev server, HMR, module discovery',\n    dev: true,\n    core: true,\n  },\n  cli: {\n    pkg: '@forinda/kickjs-cli',\n    peers: [],\n    description: 'CLI tool and code generators',\n    dev: true,\n    core: true,\n  },\n\n  // Schema validation — the validator backing env + DTO + OpenAPI\n  // schemas. `@forinda/kickjs-schema` (a core dep) wraps whichever one\n  // you pick behind `KickSchema`, but the validator itself is an\n  // optional peer of `@forinda/kickjs`, so it must be installed\n  // explicitly or the app errors at startup (\"Cannot find module\n  // 'zod'\"). `kick new` installs the chosen one; `kick add` lets an\n  // existing project add/switch.\n  zod: {\n    pkg: 'zod',\n    peers: [],\n    description: 'Zod schema validation (env, DTOs, OpenAPI) — wrap with fromZod()',\n  },\n  valibot: {\n    pkg: 'valibot',\n    peers: [],\n    description: 'Valibot schema validation — wrap with fromValibot()',\n  },\n  yup: {\n    pkg: 'yup',\n    peers: [],\n    description: 'Yup schema validation — wrap with fromYup()',\n  },\n\n  // Auth — deprecated in favour of BYO (bring-your-own) auth composed\n  // from context contributors. Still installable for existing projects;\n  // JWT is the common path, so it co-installs jsonwebtoken.\n  auth: {\n    pkg: '@forinda/kickjs-auth',\n    peers: ['jsonwebtoken'],\n    description: 'JWT, API key, OAuth strategies, @Public, @Roles (+ optional argon2/bcryptjs)',\n    deprecated:\n      'auth is moving to BYO — compose @LoadAuthUser/@RequireRole/@Public from defineContextDecorator (see the BYO Auth recipe in the docs)',\n  },\n\n  // AI — requires zod (^4) for tool/schema definitions.\n  ai: {\n    pkg: '@forinda/kickjs-ai',\n    peers: ['zod'],\n    description: 'AI toolkit — LLM providers, tool definitions from controllers',\n  },\n\n  // API\n  swagger: {\n    pkg: '@forinda/kickjs-swagger',\n    peers: [],\n    description: 'OpenAPI spec + Swagger UI + ReDoc',\n  },\n  // Database — the dialect adapters now ship as subpaths of\n  // `@forinda/kickjs-db` (`/pg`, `/sqlite`, `/mysql`), so each `kick add`\n  // pulls the core package plus the one driver you need.\n  db: {\n    pkg: '@forinda/kickjs-db',\n    peers: [],\n    description: 'kick/db core — schema DSL, migrations, KickDbClient, customType',\n  },\n  pg: {\n    pkg: '@forinda/kickjs-db',\n    peers: ['pg'],\n    description: 'kick/db + PostgreSQL driver (use @forinda/kickjs-db/pg)',\n  },\n  sqlite: {\n    pkg: '@forinda/kickjs-db',\n    peers: ['better-sqlite3'],\n    description: 'kick/db + SQLite driver (use @forinda/kickjs-db/sqlite)',\n  },\n  mysql: {\n    pkg: '@forinda/kickjs-db',\n    peers: ['mysql2'],\n    description: 'kick/db + MySQL driver (use @forinda/kickjs-db/mysql)',\n  },\n  drizzle: {\n    pkg: '@forinda/kickjs-drizzle',\n    peers: ['drizzle-orm'],\n    description: 'Drizzle ORM adapter + query builder',\n    deprecated:\n      'early-adoption adapter, no longer maintained — wire Drizzle directly (BYO), or use @forinda/kickjs-db, the built-in Kick ORM (`kick add db` / pg / sqlite / mysql)',\n  },\n  prisma: {\n    pkg: '@forinda/kickjs-prisma',\n    peers: ['@prisma/client'],\n    description: 'Prisma adapter + query builder',\n    deprecated:\n      'early-adoption adapter, no longer maintained — wire Prisma directly (BYO), or use @forinda/kickjs-db, the built-in Kick ORM (`kick add db` / pg / sqlite / mysql)',\n  },\n\n  // Real-time\n  ws: {\n    pkg: '@forinda/kickjs-ws',\n    peers: ['ws'],\n    description: 'WebSocket with @WsController decorators',\n  },\n\n  // DevTools\n  devtools: {\n    pkg: '@forinda/kickjs-devtools',\n    peers: [],\n    description: 'Development dashboard — routes, DI, metrics, health',\n    dev: true,\n  },\n\n  // Queue\n  queue: {\n    pkg: '@forinda/kickjs-queue',\n    peers: [],\n    description: 'Queue adapter (BullMQ/RabbitMQ/Kafka)',\n  },\n  'queue:bullmq': {\n    pkg: '@forinda/kickjs-queue',\n    peers: ['bullmq', 'ioredis'],\n    description: 'Queue with BullMQ + Redis',\n  },\n  'queue:rabbitmq': {\n    pkg: '@forinda/kickjs-queue',\n    peers: ['amqplib'],\n    description: 'Queue with RabbitMQ',\n  },\n  'queue:kafka': {\n    pkg: '@forinda/kickjs-queue',\n    peers: ['kafkajs'],\n    description: 'Queue with Kafka',\n  },\n  'queue:redis-pubsub': {\n    pkg: '@forinda/kickjs-queue',\n    peers: ['ioredis'],\n    description: 'Lightweight pub/sub via Redis (no persistence)',\n  },\n\n  // MCP — Model Context Protocol server\n  mcp: {\n    pkg: '@forinda/kickjs-mcp',\n    peers: ['@modelcontextprotocol/sdk'],\n    description: 'Model Context Protocol server — expose @Controller endpoints as AI tools',\n  },\n\n  // Testing\n  testing: {\n    pkg: '@forinda/kickjs-testing',\n    peers: [],\n    description: 'Test utilities and TestModule builder',\n    dev: true,\n  },\n}\n\n/**\n * Headline `kick add` packages shown after scaffolding — derived from\n * {@link PACKAGE_REGISTRY} so it can never advertise a deprecated package (the\n * old hardcoded list included auth / drizzle / prisma). Excludes core packages\n * (already installed), deprecated ones, `:` sub-variants (e.g. `queue:bullmq`),\n * and the db-dialect / schema-lib duplicates that clutter a one-line summary.\n * `kick add --list` shows the full catalog.\n */\nexport const AVAILABLE_ADD_PACKAGES = Object.entries(PACKAGE_REGISTRY)\n  .filter(\n    ([name, entry]) =>\n      !entry.core &&\n      !entry.deprecated &&\n      !name.includes(':') &&\n      !['pg', 'sqlite', 'mysql', 'zod', 'valibot', 'yup'].includes(name),\n  )\n  .map(([name]) => name)\n  .join(', ')\n\n/**\n * The `upload` catalog name is special — file uploads ship inside\n * `@forinda/kickjs` itself, so there's no package to install. What an app\n * needs is the multipart DRIVER for its HTTP runtime, and that differs per\n * engine. `planAddPackages` resolves `upload` against the configured runtime\n * (see {@link KickConfig.runtime}); `kick doctor` validates the same mapping.\n */\nexport const UPLOAD_DRIVERS: Record<\n  'express' | 'fastify' | 'h3',\n  { prod?: string; dev?: string; note: string }\n> = {\n  express: {\n    prod: 'multer',\n    dev: '@types/multer',\n    note: 'Express uploads use multer (memory/disk storage, ctx.file / ctx.files).',\n  },\n  fastify: {\n    prod: '@fastify/multipart',\n    note: 'Fastify uploads use @fastify/multipart (buffered into ctx.file / ctx.files).',\n  },\n  h3: {\n    note: 'h3 parses multipart natively (readMultipartFormData) — no driver to install.',\n  },\n}\n\nexport type AppRuntime = 'express' | 'fastify' | 'h3'\n\n/**\n * Resolve the project's HTTP runtime: the `runtime` field in kick.config\n * (authoritative — `kick new` writes it), falling back to sniffing installed\n * deps in the nearest package.json (`fastify` → fastify, `h3` → h3), else\n * `express` (the default engine). Lets `kick add upload` / `kick doctor` pick\n * the engine-correct multipart driver even in projects scaffolded before the\n * `runtime` field existed.\n */\nexport async function resolveAppRuntime(cwd = process.cwd()): Promise<AppRuntime> {\n  const config = await loadKickConfig(cwd)\n  const fromConfig = (config as { runtime?: AppRuntime } | null)?.runtime\n  if (fromConfig === 'express' || fromConfig === 'fastify' || fromConfig === 'h3') {\n    return fromConfig\n  }\n  return detectRuntimeFromDeps(cwd)\n}\n\n/** Sniff the runtime from installed deps when kick.config has no `runtime`. */\nexport function detectRuntimeFromDeps(cwd = process.cwd()): AppRuntime {\n  const dir = findUp('package.json', cwd)\n  if (dir) {\n    try {\n      const pkg = JSON.parse(readFileSync(resolve(dir, 'package.json'), 'utf-8'))\n      const deps = { ...pkg.dependencies, ...pkg.devDependencies } as Record<string, unknown>\n      if ('fastify' in deps) return 'fastify'\n      if ('h3' in deps) return 'h3'\n    } catch {\n      // ignore — fall through to the default engine\n    }\n  }\n  return 'express'\n}\n\n/**\n * Walk up from `fromDir` to filesystem root, returning the first\n * directory that contains `name`. Lets monorepo sub-packages pick up\n * lockfiles and `packageManager` fields living at the workspace root.\n */\nfunction findUp(name: string, fromDir = process.cwd()): string | null {\n  let current = fromDir\n  while (true) {\n    if (existsSync(resolve(current, name))) return current\n    const parent = dirname(current)\n    if (parent === current) return null\n    current = parent\n  }\n}\n\nfunction detectFromLockfile(): PackageManager | null {\n  if (findUp('pnpm-lock.yaml')) return 'pnpm'\n  if (findUp('yarn.lock')) return 'yarn'\n  if (findUp('bun.lockb') || findUp('bun.lock')) return 'bun'\n  if (findUp('package-lock.json')) return 'npm'\n  return null\n}\n\n/**\n * Read `packageManager` from the nearest ancestor `package.json` that\n * declares the field (corepack convention: `\"pnpm@10.0.0\"`). Climbs so\n * monorepo sub-packages inherit the workspace pm even when their own\n * package.json omits the field.\n */\nfunction packageManagerFromPackageJson(): PackageManager | null {\n  let dir: string | null = process.cwd()\n  while (dir) {\n    const pkgPath = resolve(dir, 'package.json')\n    if (existsSync(pkgPath)) {\n      try {\n        const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))\n        const field: unknown = pkg.packageManager\n        if (typeof field === 'string') {\n          const name = field.split('@')[0] as PackageManager\n          if (PACKAGE_MANAGERS.includes(name)) return name\n        }\n      } catch {\n        // ignore — keep climbing\n      }\n    }\n    const parent = dirname(dir)\n    if (parent === dir) return null\n    dir = parent\n  }\n  return null\n}\n\nexport type PackageManagerSource = 'flag' | 'config' | 'package.json' | 'lockfile' | 'default'\n\n/**\n * Resolve which package manager to use, in priority order:\n * 1. `--pm` CLI flag\n * 2. `packageManager` in kick.config\n * 3. `packageManager` in nearest ancestor package.json (corepack)\n * 4. Nearest ancestor lockfile (pnpm-lock.yaml → yarn.lock → bun.lock → package-lock.json)\n * 5. `'npm'` fallback\n *\n * Returns the chosen pm plus the source for callers that want to log\n * the resolution path.\n */\nexport async function resolvePackageManagerWithSource(\n  flagPm: string | undefined,\n): Promise<{ pm: PackageManager; source: PackageManagerSource }> {\n  if (flagPm && PACKAGE_MANAGERS.includes(flagPm as PackageManager)) {\n    return { pm: flagPm as PackageManager, source: 'flag' }\n  }\n\n  const config = await loadKickConfig(process.cwd())\n  if (config?.packageManager && PACKAGE_MANAGERS.includes(config.packageManager)) {\n    return { pm: config.packageManager, source: 'config' }\n  }\n\n  const fromPkg = packageManagerFromPackageJson()\n  if (fromPkg) return { pm: fromPkg, source: 'package.json' }\n\n  const fromLock = detectFromLockfile()\n  if (fromLock) return { pm: fromLock, source: 'lockfile' }\n\n  return { pm: 'npm', source: 'default' }\n}\n\n/** Convenience wrapper for callers that don't care about the source. */\nexport async function resolvePackageManager(flagPm: string | undefined): Promise<PackageManager> {\n  const { pm } = await resolvePackageManagerWithSource(flagPm)\n  return pm\n}\n\n/**\n * Print the package catalog. By default shows just the three core\n * packages every project always has — the optional list churns\n * (packages added, deprecated, removed) and a long enumeration in CLI\n * output / docs goes stale within a release. Pass `all = true` to dump\n * everything; that's what `kick add --list --all` triggers when an\n * adopter genuinely wants the live catalog.\n */\nexport function printPackageList(all = false): void {\n  const entries = Object.entries(PACKAGE_REGISTRY)\n  const maxName = Math.max(...entries.map(([k]) => k.length))\n  const core = entries.filter(([, info]) => info.core)\n  const optional = entries.filter(([, info]) => !info.core)\n\n  const formatRow = ([name, info]: [string, PackageEntry]): string => {\n    const padded = name.padEnd(maxName + 2)\n    const peers = info.peers.length ? ` (+ ${info.peers.join(', ')})` : ''\n    const deprecated = info.deprecated ? ` [DEPRECATED — ${info.deprecated}]` : ''\n    return `    ${padded} ${info.description}${peers}${deprecated}`\n  }\n\n  console.log('\\n  Core packages (always installed by `kick new`):\\n')\n  for (const row of core) console.log(formatRow(row))\n\n  if (all) {\n    console.log('\\n  Optional packages (add as needed):\\n')\n    for (const row of optional) console.log(formatRow(row))\n  } else {\n    console.log(`\\n  Plus ${optional.length} optional packages (auth, swagger, db, queue, …).`)\n    console.log('  Run `kick add --list --all` for the full catalog.')\n  }\n\n  console.log('\\n  Usage: kick add ai db swagger')\n  console.log('         kick add queue:bullmq')\n  console.log('         kick add upload   # installs the multipart driver for your runtime')\n  console.log()\n}\n\nexport interface AddPlan {\n  prodDeps: string[]\n  devDeps: string[]\n  unknown: string[]\n  /** Deprecation notices for requested entries — print, then install anyway. */\n  warnings: string[]\n  /** Informational notes (e.g. the upload driver chosen for the runtime). */\n  notices: string[]\n}\n\n/**\n * Pure resolution step for `kick add` — maps requested catalog names to\n * the npm packages (plus peers) to install, split prod/dev. Kept free\n * of I/O so the catalog rules (dev defaults, deprecations, unknown\n * handling) are unit-testable without spawning a package manager.\n */\nexport function planAddPackages(\n  packages: string[],\n  forceDev: boolean,\n  runtime: AppRuntime = 'express',\n): AddPlan {\n  const prodDeps = new Set<string>()\n  const devDeps = new Set<string>()\n  const unknown: string[] = []\n  const warnings: string[] = []\n  const notices: string[] = []\n\n  for (const name of packages) {\n    // `upload` isn't a package — it's the runtime's multipart driver. File\n    // uploads ship in @forinda/kickjs; only the engine backend needs adding.\n    if (name === 'upload') {\n      const driver = UPLOAD_DRIVERS[runtime]\n      notices.push(`upload (${runtime}): ${driver.note}`)\n      if (driver.prod) (forceDev ? devDeps : prodDeps).add(driver.prod)\n      if (driver.dev) devDeps.add(driver.dev)\n      continue\n    }\n\n    const entry = PACKAGE_REGISTRY[name]\n    if (!entry) {\n      unknown.push(name)\n      continue\n    }\n    if (entry.deprecated) {\n      warnings.push(`'${name}' (${entry.pkg}) is deprecated — ${entry.deprecated}`)\n    }\n    const target = forceDev || entry.dev ? devDeps : prodDeps\n    target.add(entry.pkg)\n    for (const peer of entry.peers) {\n      target.add(peer)\n    }\n  }\n\n  return { prodDeps: [...prodDeps], devDeps: [...devDeps], unknown, warnings, notices }\n}\n\nexport function registerListCommand(program: Command): void {\n  program\n    .command('list')\n    .alias('ls')\n    .description('List KickJS packages (core only; pair with --all for the full catalog)')\n    .option('--all', 'Include the full optional catalog')\n    .action((opts: { all?: boolean }) => {\n      printPackageList(Boolean(opts.all))\n    })\n}\n\nexport function registerAddCommand(program: Command): void {\n  program\n    .command('add [packages...]')\n    .description('Add KickJS packages with their required dependencies')\n    .option('--pm <manager>', 'Package manager override')\n    .option('-D, --dev', 'Install as dev dependency')\n    .option('--list', 'List packages (core only by default; pair with --all)')\n    .option('--all', 'When listing, include the full optional catalog')\n    .action(async (packages: string[], opts: any) => {\n      // List mode\n      if (opts.list || packages.length === 0) {\n        printPackageList(Boolean(opts.all))\n        return\n      }\n\n      const { pm, source } = await resolvePackageManagerWithSource(opts.pm)\n      console.log(`\\n  Using ${pm} (resolved from ${source})`)\n      // Resolve the runtime so `kick add upload` installs the right multipart\n      // driver (express → multer, fastify → @fastify/multipart, h3 → none).\n      const runtime = await resolveAppRuntime(process.cwd())\n      const { prodDeps, devDeps, unknown, warnings, notices } = planAddPackages(\n        packages,\n        Boolean(opts.dev),\n        runtime,\n      )\n\n      for (const warning of warnings) {\n        console.warn(`\\n  WARNING: ${warning}`)\n      }\n\n      for (const notice of notices) {\n        console.log(`\\n  ${notice}`)\n      }\n\n      if (unknown.length > 0) {\n        console.log(`\\n  Unknown packages: ${unknown.join(', ')}`)\n        console.log('  Run \"kick add --list\" to see available packages.\\n')\n        if (prodDeps.length === 0 && devDeps.length === 0) return\n      }\n\n      // Install production dependencies\n      if (prodDeps.length > 0) {\n        const deps = prodDeps\n        const cmd = `${pm} add ${deps.join(' ')}`\n        console.log(`\\n  Installing ${deps.length} dependency(ies):`)\n        for (const dep of deps) console.log(`    + ${dep}`)\n        console.log()\n        try {\n          execSync(cmd, { stdio: 'inherit' })\n        } catch {\n          console.log(`\\n  Installation failed. Run manually:\\n    ${cmd}\\n`)\n        }\n      }\n\n      // Install dev dependencies\n      if (devDeps.length > 0) {\n        const deps = devDeps\n        const cmd = `${pm} add -D ${deps.join(' ')}`\n        console.log(`\\n  Installing ${deps.length} dev dependency(ies):`)\n        for (const dep of deps) console.log(`    + ${dep} (dev)`)\n        console.log()\n        try {\n          execSync(cmd, { stdio: 'inherit' })\n        } catch {\n          console.log(`\\n  Installation failed. Run manually:\\n    ${cmd}\\n`)\n        }\n      }\n\n      console.log('  Done!\\n')\n    })\n}\n","import { join, dirname } from 'node:path'\nimport { execFileSync, execSync } from 'node:child_process'\nimport { readFileSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\nimport { writeFileSafe } from '../utils/fs'\nimport {\n  generatePackageJson,\n  generateViteConfig,\n  generateTsConfig,\n  generatePrettierConfig,\n  generateEditorConfig,\n  generateGitIgnore,\n  generateGitAttributes,\n  generateEnv,\n  generateEnvExample,\n  generateVitestConfig,\n} from './templates/project-config'\nimport {\n  generateEntryFile,\n  generateEnvFile,\n  generateModulesIndex,\n  generateKickConfig,\n  generateHelloService,\n  generateHelloController,\n  generateHelloModule,\n} from './templates/project-app'\nimport { generateReadme } from './templates/project-docs'\nimport { AVAILABLE_ADD_PACKAGES } from '../commands/add'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\nconst cliPkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'))\nconst CLI_VERSION_FALLBACK = `^${cliPkg.version}`\n\n/**\n * Sibling `@forinda/kickjs-*` packages whose versions are resolved\n * independently when scaffolding a new project. Each entry is queried\n * via `npm view <name> version`; failure falls back to the CLI's own\n * version (`CLI_VERSION_FALLBACK`).\n *\n * Per-package independent versioning landed with changesets — before\n * that, every sibling shipped in lockstep with the CLI so a single\n * pin was correct. Now `@forinda/kickjs@5.5.0` may pair with\n * `@forinda/kickjs-cli@5.4.2` and `@forinda/kickjs-swagger@5.3.1`;\n * pinning them all to the CLI's version under-installs adopters.\n */\nconst SIBLING_PACKAGES = [\n  '@forinda/kickjs',\n  '@forinda/kickjs-cli',\n  '@forinda/kickjs-schema',\n  '@forinda/kickjs-vite',\n  '@forinda/kickjs-swagger',\n  '@forinda/kickjs-ws',\n  '@forinda/kickjs-queue',\n  '@forinda/kickjs-devtools',\n  '@forinda/kickjs-testing',\n] as const\n\n/**\n * Resolve the latest published version of every sibling package via\n * `npm view <name> version` (via execFileSync — no shell, no\n * injection vector). Each query has a short timeout; failures fall\n * back to the CLI's own version with a `^` prefix so the scaffold\n * stays usable offline.\n */\nasync function resolveSiblingVersions(): Promise<Record<string, string>> {\n  const results = await Promise.all(\n    SIBLING_PACKAGES.map(async (name) => {\n      try {\n        const out = execFileSync('npm', ['view', name, 'version'], {\n          encoding: 'utf-8',\n          timeout: 5000,\n          stdio: ['ignore', 'pipe', 'ignore'],\n        })\n          .toString()\n          .trim()\n        if (out && /^\\d+\\.\\d+\\.\\d+/.test(out)) {\n          return [name, `^${out}`] as const\n        }\n      } catch {\n        // Network failure / package not yet published / npm\n        // unavailable. Fall back to CLI version below.\n      }\n      return [name, CLI_VERSION_FALLBACK] as const\n    }),\n  )\n  return Object.fromEntries(results)\n}\n\n/**\n * Resolve the published version of a package at a given dist-tag\n * (`npm view <name>@<tag> version`). Returns `null` on any failure. Used\n * to pin `@forinda/kickjs` to the `alpha` channel when scaffolding a\n * Fastify / h3 app — the engine subpaths (`@forinda/kickjs/fastify`,\n * `/h3`) ship only on the alpha until the runtimes land in a stable\n * release, so the default `latest` resolution would install a kickjs\n * that doesn't export them (→ Vite \"./h3 is not exported\" at boot).\n * Returns the bare version; the caller applies a `^` range so the project\n * floats to newer alphas and auto-graduates to stable (a caret over a\n * prerelease matches same-tuple prereleases ≥ it, plus later stables `< next\n * major`).\n */\nfunction resolveVersionAtTag(name: string, tag: string): string | null {\n  try {\n    const out = execFileSync('npm', ['view', `${name}@${tag}`, 'version'], {\n      encoding: 'utf-8',\n      timeout: 5000,\n      stdio: ['ignore', 'pipe', 'ignore'],\n    })\n      .toString()\n      .trim()\n    return out && /^\\d+\\.\\d+\\.\\d+/.test(out) ? out : null\n  } catch {\n    return null\n  }\n}\n\n/**\n * Whether the package at a given dist-tag exports a subpath (e.g. `./h3`).\n * Reads the `exports` map via `npm view <name>@<tag> exports --json`. Used to\n * gate the alpha-pin: if `latest` already ships the engine subpath, the runtime\n * has graduated to stable and we should NOT downgrade to an older alpha.\n * Returns `false` on any failure (missing field / network / unparseable) so the\n * caller treats \"unknown\" as \"not present\" and falls through to the alpha path.\n */\n/** Strip a leading range operator (`^1.2.3` / `~1.2.3` → `1.2.3`). */\nfunction stripRange(range: string | undefined): string {\n  return (range ?? '').replace(/^[\\^~>=<\\s]+/, '')\n}\n\n/**\n * Compare the release cores (major.minor.patch, ignoring any `-prerelease`\n * suffix) of two versions: is `a` >= `b`? Used to guard the alpha-pin so a\n * package is never downgraded onto a stale prerelease whose stable line has\n * already moved past it. A coarse compare is enough here — we only need\n * \"is this alpha at least as new as the stable we'd otherwise install\".\n */\nfunction baseVersionGte(a: string, b: string): boolean {\n  const core = (v: string): number[] =>\n    stripRange(v)\n      .split('-')[0]!\n      .split('.')\n      .map((n) => Number.parseInt(n, 10) || 0)\n  const [a0 = 0, a1 = 0, a2 = 0] = core(a)\n  const [b0 = 0, b1 = 0, b2 = 0] = core(b)\n  if (a0 !== b0) return a0 > b0\n  if (a1 !== b1) return a1 > b1\n  return a2 >= b2\n}\n\nfunction tagExportsSubpath(name: string, tag: string, subpath: string): boolean {\n  try {\n    const out = execFileSync('npm', ['view', `${name}@${tag}`, 'exports', '--json'], {\n      encoding: 'utf-8',\n      timeout: 5000,\n      stdio: ['ignore', 'pipe', 'ignore'],\n    })\n      .toString()\n      .trim()\n    if (!out) return false\n    const exportsMap = JSON.parse(out) as Record<string, unknown>\n    return Object.prototype.hasOwnProperty.call(exportsMap, subpath)\n  } catch {\n    return false\n  }\n}\n\ntype ProjectTemplate = 'rest' | 'minimal'\ntype SchemaLib = 'zod' | 'valibot' | 'yup'\n\ninterface InitProjectOptions {\n  name: string\n  directory: string\n  packageManager?: 'pnpm' | 'npm' | 'yarn' | 'bun'\n  initGit?: boolean\n  installDeps?: boolean\n  template?: ProjectTemplate\n  defaultRepo?: string\n  packages?: string[]\n  /** Schema library to scaffold env / DTOs with. Defaults to `zod`. */\n  schemaLib?: SchemaLib\n  /** HTTP engine to scaffold. Defaults to `express`. */\n  runtime?: 'express' | 'fastify' | 'h3'\n}\n\n/** Scaffold a new KickJS project */\nexport async function initProject(options: InitProjectOptions): Promise<void> {\n  const {\n    name,\n    directory,\n    packageManager = 'pnpm',\n    template = 'rest',\n    defaultRepo = 'inmemory',\n    packages = [],\n    schemaLib = 'zod',\n    runtime = 'express',\n  } = options\n  const dir = directory\n\n  const log = (msg: string) => console.log(`  ${msg}`)\n\n  console.log(`\\n  Creating KickJS project: ${name}\\n`)\n\n  // Resolve published version of every sibling kickjs package in\n  // parallel. Per-package independent versioning means\n  // `@forinda/kickjs@5.5.0` may pair with `@forinda/kickjs-cli@5.4.2`\n  // and `@forinda/kickjs-swagger@5.3.1`; pinning every dep to the\n  // CLI's own version under-installs adopters whenever a sibling\n  // bumps independently. `npm view` fallback keeps the scaffold\n  // working offline.\n  log('Resolving package versions...')\n  const versions = await resolveSiblingVersions()\n\n  // The pluggable-runtimes work (Fastify / h3 engine subpaths, the\n  // `kick/runtime` typegen, `kick add upload`, `kick doctor` runtime checks)\n  // ships only on the `alpha` channel until it lands in a stable release. So a\n  // non-Express scaffold needs the alpha of every package that carries runtime\n  // behavior, not just `@forinda/kickjs`:\n  //   - `@forinda/kickjs`       — the `./fastify` / `./h3` export subpaths the\n  //                               app imports (stable lacks them → Vite boot\n  //                               error `\"./h3\" is not exported`).\n  //   - `@forinda/kickjs-cli`   — `--runtime`, `kick add upload`, `kick doctor`,\n  //                               the `kick/runtime` typegen plugin.\n  //   - `@forinda/kickjs-vite`  — the dev loop co-versioned with the above.\n  // Gated on whether `@forinda/kickjs@latest` already exports the chosen engine\n  // subpath: once that's true the runtimes are stable and we keep `latest` for\n  // everything (self-retiring — no code change needed at graduation). Each pin\n  // is guarded so it never DOWNGRADES (an alpha can be older than latest — e.g.\n  // a package whose stable moved on past an old prerelease). Express is exempt.\n  if (runtime !== 'express') {\n    const subpath = `./${runtime}` // './fastify' | './h3'\n    if (tagExportsSubpath('@forinda/kickjs', 'latest', subpath)) {\n      log(`Using @forinda/kickjs@latest (stable ships the ${runtime} runtime)`)\n    } else {\n      const RUNTIME_PKGS = ['@forinda/kickjs', '@forinda/kickjs-cli', '@forinda/kickjs-vite']\n      const pinned: string[] = []\n      let kickjsPinned = false\n      for (const pkg of RUNTIME_PKGS) {\n        const alpha = resolveVersionAtTag(pkg, 'alpha')\n        // Only switch when the alpha is newer-or-equal to the stable we'd\n        // otherwise install — never downgrade onto a stale prerelease. Use a\n        // `^` range (not an exact pin) so the project picks up newer alphas and\n        // auto-graduates to the stable release once it ships.\n        if (alpha && baseVersionGte(alpha, stripRange(versions[pkg]))) {\n          versions[pkg] = `^${alpha}`\n          pinned.push(`${pkg}@^${alpha}`)\n          if (pkg === '@forinda/kickjs') kickjsPinned = true\n        }\n      }\n      if (kickjsPinned) {\n        log(`Using the alpha channel for the ${runtime} runtime: ${pinned.join(', ')}`)\n      } else {\n        log(\n          `WARNING: could not resolve @forinda/kickjs@alpha — the ${runtime} runtime subpath ` +\n            `may be missing. After install, run: ${packageManager} add @forinda/kickjs@alpha`,\n        )\n      }\n    }\n  }\n\n  // ── package.json — template-aware deps ────────────────────────────\n  await writeFileSafe(\n    join(dir, 'package.json'),\n    generatePackageJson(name, template, versions, packages, schemaLib, runtime),\n  )\n\n  // ── vite.config.ts — enables HMR + SWC for decorators ──────────────\n  await writeFileSafe(join(dir, 'vite.config.ts'), generateViteConfig())\n\n  // ── tsconfig.json ───────────────────────────────────────────────────\n  await writeFileSafe(join(dir, 'tsconfig.json'), generateTsConfig())\n\n  // ── .prettierrc ─────────────────────────────────────────────────────\n  await writeFileSafe(join(dir, '.prettierrc'), generatePrettierConfig())\n\n  // ── .editorconfig ─────────────────────────────────────────────────────\n  await writeFileSafe(join(dir, '.editorconfig'), generateEditorConfig())\n\n  // ── .gitignore ──────────────────────────────────────────────────────\n  await writeFileSafe(join(dir, '.gitignore'), generateGitIgnore())\n\n  // ── .gitattributes ────────────────────────────────────────────────────\n  await writeFileSafe(join(dir, '.gitattributes'), generateGitAttributes())\n\n  // ── .env ────────────────────────────────────────────────────────────\n  await writeFileSafe(join(dir, '.env'), generateEnv())\n\n  await writeFileSafe(join(dir, '.env.example'), generateEnvExample())\n\n  // ── src/config/index.ts — typed env schema (read by `kick typegen`) ─\n  // Lives under `src/config/` so the framework's \"config\" concept has a\n  // single, conventional home. Old projects with `src/env.ts` still\n  // work — `detectEnvFile()` searches both locations.\n  await writeFileSafe(join(dir, 'src/config/index.ts'), generateEnvFile(schemaLib))\n\n  // ── src/index.ts — template-aware entry point ─────────────────────\n  await writeFileSafe(\n    join(dir, 'src/index.ts'),\n    generateEntryFile(name, template, cliPkg.version, packages, runtime),\n  )\n\n  // ── src/modules/index.ts ────────────────────────────────────────────\n  await writeFileSafe(join(dir, 'src/modules/index.ts'), generateModulesIndex())\n\n  // ── src/modules/hello/ — sample module ─────────────────────────────\n  await writeFileSafe(join(dir, 'src/modules/hello/hello.service.ts'), generateHelloService())\n  await writeFileSafe(join(dir, 'src/modules/hello/hello.controller.ts'), generateHelloController())\n  await writeFileSafe(join(dir, 'src/modules/hello/hello.module.ts'), generateHelloModule())\n\n  // ── kick.config.ts — CLI configuration ─────────────────────────────\n  await writeFileSafe(\n    join(dir, 'kick.config.ts'),\n    generateKickConfig(template, defaultRepo, packageManager, runtime),\n  )\n\n  // ── vitest.config.ts ────────────────────────────────────────────────\n  await writeFileSafe(join(dir, 'vitest.config.ts'), generateVitestConfig())\n\n  // ── README.md ────────────────────────────────────────────────────────\n  await writeFileSafe(join(dir, 'README.md'), generateReadme(name, template, packageManager))\n\n  // ── Agent docs ──────────────────────────────────────────────────────\n  // Delegate to `generateAgentDocs()` so `kick new` emits the same\n  // `.agents/` subfolder layout as `kick g agents -f`. Otherwise the\n  // two paths drifted: kick new was writing the legacy flat layout\n  // (root-level AGENTS.md + kickjs-skills.md) while kick g agents\n  // emits the per-skill SKILL.md format under .agents/. `force: true`\n  // because the project directory is fresh — no overwrite prompts\n  // make sense during init.\n  const { generateAgentDocs } = await import('./agent-docs')\n  await generateAgentDocs({\n    outDir: dir,\n    name,\n    pm: packageManager,\n    template,\n    only: 'all',\n    force: true,\n  })\n\n  // ── Install Dependencies ────────────────────────────────────────────\n  // Install BEFORE git init so the lockfile is included in the first commit.\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  // ── Initial typegen ────────────────────────────────────────────────\n  // Run typegen once so the freshly-scaffolded HelloController's\n  // `Ctx<KickRoutes.HelloController['index']>` references resolve in\n  // the user's editor immediately. Failures are non-fatal.\n  try {\n    const { runTypegen } = await import('../typegen')\n    await runTypegen({ cwd: dir, allowDuplicates: true, silent: true })\n  } catch {\n    // First-run typegen errors are non-fatal — `kick dev` will retry.\n  }\n\n  // ── Git Init ─────────────────────────────────────────────────────────\n  // Runs after install + typegen so lockfile and generated types are\n  // included in the initial commit.\n  if (options.initGit) {\n    try {\n      execSync('git init', { cwd: dir, stdio: 'pipe' })\n      execSync('git branch -M main', { 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      log('Git repository initialized')\n    } catch {\n      log('Warning: git init failed (git may not be installed)')\n    }\n  }\n\n  console.log('\\n  Project scaffolded successfully!')\n  console.log()\n\n  const needsCd = dir !== process.cwd()\n  log('Next steps:')\n  if (needsCd) log(`  cd ${name}`)\n  if (!options.installDeps) log(`  ${packageManager} install`)\n\n  const genHint: Record<string, string> = {\n    rest: 'kick g module user',\n    ddd: 'kick g module user --repo drizzle',\n    cqrs: 'kick g module user --pattern cqrs',\n    minimal: '# add your routes to src/index.ts',\n  }\n  log(`  ${genHint[template] ?? genHint.rest}`)\n  log('  kick dev')\n  log('')\n  log('Commands:')\n  log('  kick dev                  Start dev server with Vite HMR')\n  log('  kick build                Production build via Vite')\n  log('  kick start                Run production build')\n  log('')\n  log('Generators:')\n  log('  kick g module <name>      Full DDD module (controller, DTOs, use-cases, repo)')\n  log('  kick g scaffold <n> <f..> CRUD module from field definitions')\n  log('  kick g controller <name>  Standalone controller')\n  log('  kick g service <name>     @Service() class')\n  log('  kick g middleware <name>   Express middleware')\n  log('  kick g guard <name>       Route guard (auth, roles, etc.)')\n  log('  kick g adapter <name>     AppAdapter with lifecycle hooks')\n  log('  kick g dto <name>         Zod DTO schema')\n  log('  kick g config             Generate kick.config.ts')\n  log('')\n  log('Add packages:')\n  log('  kick add <pkg>            Install a KickJS package + peers')\n  log('  kick add --list           Show all available packages')\n  log('')\n  log(`Available: ${AVAILABLE_ADD_PACKAGES}`)\n  log('')\n}\n","/**\n * Deduplicating reporter for typegen failures in `kick dev` watch mode.\n *\n * The watch pipeline used to swallow errors entirely (`.catch(() => {})`),\n * which left adopters debugging stale `.kickjs/types` with no signal.\n * This reporter warns on every NEW failure message per source, stays\n * quiet for repeats of the same message (each save in a broken state\n * would otherwise re-print it), and re-arms once the source succeeds\n * again so a recurring failure after a fix re-warns.\n */\nexport interface TypegenErrorReporter {\n  /** Report a failure for `source`; emits only if the message changed. */\n  report(source: string, err: unknown): void\n  /** Mark `source` healthy — the next failure emits even if identical. */\n  clear(source: string): void\n}\n\nexport function createTypegenErrorReporter(emit: (message: string) => void): TypegenErrorReporter {\n  const lastMessage = new Map<string, string>()\n  return {\n    report(source, err) {\n      const msg = err instanceof Error ? err.message : String(err)\n      if (lastMessage.get(source) === msg) return\n      lastMessage.set(source, msg)\n      emit(`  kick typegen: ${source} pass failed (${msg}) — types in .kickjs/types may be stale`)\n    },\n    clear(source) {\n      lastMessage.delete(source)\n    },\n  }\n}\n","/**\n * Debounced typegen-on-save watcher — the engine behind `kick dev`'s\n * file-change handling, extracted so `@forinda/kickjs-vite` can run the\n * SAME pipeline when the adopter boots plain `vite` (or any other\n * Vite-embedding tool) instead of `kick dev`.\n *\n * Behaviour (verbatim from the original inline implementation):\n *  - Watcher events batch into one debounced pass (default 100ms).\n *  - `.ts/.tsx/.mts/.cts` changes feed a precise `{changed, removed}`\n *    delta to the incremental scanner; `unlinkDir` forces a full walk\n *    (a dir removal can't be expressed as a per-file delta).\n *  - Files under an `assetMap.<ns>.src` dir mark the pass asset-dirty,\n *    driving an incremental `buildAssets` sweep.\n *  - `.kickjs/**` and `.d.ts` events are ignored (typegen's own output).\n *  - Failures surface through a deduplicating reporter (one warning per\n *    NEW failure message per source; quiet on repeats; re-arms after a\n *    successful pass).\n *\n * Exactly one watcher should own typegen per dev process. `kick dev`\n * claims ownership via {@link TYPEGEN_OWNER_KEY} on `globalThis` before\n * booting Vite; the vite plugin checks the marker and stands down.\n */\nimport path from 'node:path'\n\nimport type { KickConfig } from '../config'\nimport type { runTypegen, writeTypegenArtifacts } from './index'\nimport type { runAllPluginTypegens } from './run-plugins'\nimport type { buildAssets } from '../asset-manager/build'\nimport { createTypegenErrorReporter } from '../commands/typegen-error-reporter'\nimport type { ScanDelta } from './scanner'\n\n/**\n * `globalThis` key claiming typegen ownership for the current process.\n * Set by `kick dev` (which boots Vite in-process) so the vite plugin's\n * own watcher never double-runs the pipeline.\n */\nexport const TYPEGEN_OWNER_KEY = '__kickjs_typegen_owner'\n\nexport type TypegenWatchEvent = 'add' | 'change' | 'unlink' | 'unlinkDir'\n\n/** Injectable pipeline — production uses the real functions. */\nexport interface TypegenDevPipeline {\n  runTypegen: typeof runTypegen\n  runAllPluginTypegens: typeof runAllPluginTypegens\n  writeTypegenArtifacts: typeof writeTypegenArtifacts\n  buildAssets: typeof buildAssets\n}\n\nexport interface TypegenDevWatcherOptions {\n  cwd: string\n  /** Pre-loaded kick.config.ts (null when the project has none). */\n  config: KickConfig | null\n  /**\n   * Warning sink — wired by the caller to `console.warn` plus whatever\n   * HMR broadcast it has (e.g. the `kickjs:typegen-error` custom event).\n   */\n  emitWarning: (message: string) => void\n  /**\n   * Invoked after each pass's plugin chain settles (success or failure).\n   * `kick dev` uses it to schedule the `--typecheck` worker against\n   * fresh `.kickjs/types`.\n   */\n  onPassComplete?: () => void\n  /** Debounce window in ms. @default 100 */\n  debounceMs?: number\n  /** Test seam — defaults to the real typegen pipeline. */\n  pipeline?: TypegenDevPipeline\n}\n\nexport interface TypegenDevWatcher {\n  /** Feed a chokidar-style watcher event into the debounce window. */\n  handleWatchEvent(event: TypegenWatchEvent, file: string): void\n  /**\n   * Run one full (non-incremental) pass immediately — startup catch-up\n   * for callers that didn't run typegen before the server booted.\n   */\n  runOnce(): void\n  /**\n   * Absolute `assetMap.<ns>.src` roots. Vite's default watcher ignores\n   * extensions it doesn't compile, so callers should `watcher.add(...)`\n   * these to receive template-file events at all.\n   */\n  assetSrcRoots: readonly string[]\n  /** Cancel any pending debounced pass. */\n  dispose(): void\n}\n\nexport function createTypegenDevWatcher(opts: TypegenDevWatcherOptions): TypegenDevWatcher {\n  const { cwd, config } = opts\n  const debounceMs = opts.debounceMs ?? 100\n  // Default pipeline resolves lazily — a static import would drag the\n  // whole generator/typegen graph (including dist-layout-only module\n  // initializers) into every consumer of this module.\n  const pipeline: TypegenDevPipeline = opts.pipeline ?? {\n    runTypegen: async (o) => (await import('./index')).runTypegen(o),\n    runAllPluginTypegens: async (o) => (await import('./run-plugins')).runAllPluginTypegens(o),\n    writeTypegenArtifacts: async (dir, results, silent) =>\n      (await import('./index')).writeTypegenArtifacts(dir, results, silent),\n    buildAssets: async (cfg, o) => (await import('../asset-manager/build')).buildAssets(cfg, o),\n  }\n\n  const schemaValidator = config?.typegen?.schemaValidator ?? 'zod'\n  const envFile = config?.typegen?.envFile\n  const typesOutDir = path.resolve(cwd, config?.typegen?.outDir ?? '.kickjs/types')\n\n  const assetSrcRoots: readonly string[] = config?.assetMap\n    ? Object.values(config.assetMap)\n        .map((entry) => entry?.src)\n        .filter((src): src is string => typeof src === 'string' && src.length > 0)\n        .map((src) => path.resolve(cwd, src))\n    : []\n  const hasAssetMap = !!config?.assetMap && Object.keys(config.assetMap).length > 0\n  // Normalize BOTH sides to forward slashes before comparing — chokidar\n  // emits native separators on Windows while `path.resolve` produces\n  // backslash roots, so a raw startsWith would miss either direction.\n  const toPosix = (p: string): string => p.replaceAll('\\\\', '/')\n  const assetRootsPosix = assetSrcRoots.map(toPosix)\n  const isAssetFile = (file: string): boolean => {\n    const posix = toPosix(file)\n    return assetRootsPosix.some((root) => posix === root || posix.startsWith(`${root}/`))\n  }\n\n  const reporter = createTypegenErrorReporter(opts.emitWarning)\n\n  let timer: ReturnType<typeof setTimeout> | null = null\n  let disposed = false\n  const pendingChanged = new Set<string>()\n  const pendingRemoved = new Set<string>()\n  let forceFullScan = false\n  let assetDirty = false\n\n  function firePass(delta: ScanDelta | undefined, rebuildAssets: boolean): void {\n    pipeline\n      .runTypegen({\n        cwd,\n        silent: true,\n        allowDuplicates: true,\n        schemaValidator,\n        envFile,\n        srcDir: config?.typegen?.srcDir,\n        outDir: config?.typegen?.outDir,\n        assetMap: config?.assetMap,\n        changedFiles: delta,\n        // Plugin pipeline runs separately just below; opting out here\n        // avoids double-running it on every debounced trigger.\n        runPlugins: false,\n      })\n      .then(() => reporter.clear('scan'))\n      .catch((err) => reporter.report('scan', err))\n    pipeline\n      .runAllPluginTypegens({ cwd, config, silent: true, changedFiles: delta })\n      .then((r) => pipeline.writeTypegenArtifacts(typesOutDir, r, true))\n      .then(() => reporter.clear('plugins'))\n      .catch((err) => reporter.report('plugins', err))\n      // Post-pass hook AFTER the plugin chain settles so consumers (the\n      // --typecheck worker) see the freshest .kickjs/types this window\n      // produced.\n      .finally(() => opts.onPassComplete?.())\n    if (rebuildAssets && config) {\n      pipeline.buildAssets(config, { cwd, silent: true }).catch(() => {})\n    }\n  }\n\n  function flush(): void {\n    // `undefined` delta → full scan (the `unlinkDir` correctness path).\n    const delta = forceFullScan\n      ? undefined\n      : { changed: [...pendingChanged], removed: [...pendingRemoved] }\n    const rebuildAssets = assetDirty\n    pendingChanged.clear()\n    pendingRemoved.clear()\n    forceFullScan = false\n    assetDirty = false\n    firePass(delta, rebuildAssets)\n  }\n\n  return {\n    assetSrcRoots,\n\n    handleWatchEvent(event, file) {\n      if (disposed) return\n      // Typegen's own output directory — separator-aware so a file\n      // merely NAMED like `my.kickjs.backup.ts` isn't filtered.\n      if (toPosix(file).includes('/.kickjs/')) return\n      if (event === 'unlinkDir') {\n        // Only meaningful if the removed dir could have held scanned\n        // sources or watched assets; cheap to just force a full scan.\n        forceFullScan = true\n        if (hasAssetMap) assetDirty = true\n      } else {\n        if (file.endsWith('.d.ts')) return\n        const isTs = /\\.(ts|tsx|mts|cts)$/.test(file)\n        const isAsset = isAssetFile(file)\n        if (!isTs && !isAsset) return\n        if (isAsset && hasAssetMap) assetDirty = true\n        // Only `.ts` files participate in the source scan delta. Asset-\n        // only changes still trigger the pass (so the asset plugin\n        // re-emits) but contribute nothing to the scan — an empty `.ts`\n        // delta makes the incremental scan a near-instant cache replay.\n        if (isTs) {\n          if (event === 'unlink') {\n            pendingRemoved.add(file)\n            pendingChanged.delete(file)\n          } else {\n            pendingChanged.add(file)\n            pendingRemoved.delete(file)\n          }\n        }\n      }\n      if (timer) clearTimeout(timer)\n      timer = setTimeout(flush, debounceMs)\n    },\n\n    runOnce() {\n      if (disposed) return\n      firePass(undefined, hasAssetMap)\n    },\n\n    dispose() {\n      disposed = true\n      if (timer) clearTimeout(timer)\n      timer = null\n    },\n  }\n}\n","import { pathToFileURL } from 'node:url'\nimport { resolve } from 'node:path'\nimport { toPascalCase, toCamelCase, toKebabCase, pluralize } from '../utils/naming'\nimport { findProjectRoot } from '../utils/project-root'\nimport type { GeneratorContext } from './define'\n\n/** Convert any string to snake_case (`UserPost` / `user-post` → `user_post`). */\nfunction toSnakeCase(name: string): string {\n  return toKebabCase(name).replace(/-/g, '_')\n}\n\n/**\n * Build a {@link GeneratorContext} from the raw name + invocation\n * arguments. Centralises the case-transformation logic so every plugin\n * generator sees the same shape regardless of how the name was typed\n * on the command line (`Post` vs `post` vs `user_post`).\n */\nexport function buildGeneratorContext(input: {\n  name: string\n  args?: string[]\n  flags?: Record<string, string | boolean>\n  modulesDir?: string\n  cwd?: string\n  /**\n   * Resolved project root. When omitted, derived from {@link cwd} via\n   * `findProjectRoot()` so adopter-facing call sites stay zero-config.\n   * Callers that already know the root (e.g. `cli.ts` after one upfront\n   * resolution) should pass it through to avoid redundant fs walks.\n   */\n  projectRoot?: string\n  pluralize?: boolean\n}): GeneratorContext {\n  const cwd = input.cwd ?? process.cwd()\n  const projectRoot = input.projectRoot ?? findProjectRoot(cwd)\n  const usePlural = input.pluralize ?? true\n\n  const pascal = toPascalCase(input.name)\n  const camel = toCamelCase(input.name)\n  const kebab = toKebabCase(input.name)\n  const snake = toSnakeCase(input.name)\n\n  const ctx: GeneratorContext = {\n    name: input.name,\n    pascal,\n    camel,\n    kebab,\n    snake,\n    modulesDir: input.modulesDir ?? 'src/modules',\n    cwd,\n    projectRoot,\n    args: input.args ?? [],\n    flags: input.flags ?? {},\n  }\n\n  if (usePlural) {\n    const pluralKebab = pluralize(kebab)\n    ctx.pluralKebab = pluralKebab\n    ctx.pluralPascal = toPascalCase(pluralKebab)\n    ctx.pluralCamel = toCamelCase(pluralKebab)\n  }\n\n  return ctx\n}\n\n/** Resolve a generator output path against the context's cwd. */\nexport function resolveGeneratorPath(ctx: GeneratorContext, path: string): string {\n  return resolve(ctx.cwd, path)\n}\n\n/**\n * Dynamic-import a generator manifest file. Wraps `pathToFileURL` so\n * callers don't have to think about Windows/Unix path quirks.\n */\nexport async function importManifest(absPath: string): Promise<unknown> {\n  return import(pathToFileURL(absPath).href)\n}\n","import { readFile } from 'node:fs/promises'\nimport { resolve, dirname } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport type { GeneratorSpec } from './define'\nimport { importManifest } from './context'\n\n/**\n * One row in the discovered registry. `source` is the npm package name\n * the generator came from — surfaced in error messages so adopters can\n * see which plugin owns a given generator.\n */\nexport interface DiscoveredGenerator {\n  source: string\n  spec: GeneratorSpec\n}\n\n/**\n * Plugin discovery result, kept around even when no generators were\n * registered so callers can distinguish \"no plugins installed\" from\n * \"no plugins matched the requested name.\"\n */\nexport interface DiscoveryResult {\n  generators: DiscoveredGenerator[]\n  /** Packages whose `kickjs.generators` was loaded successfully. */\n  loaded: string[]\n  /**\n   * Packages we tried to load but failed — typically a missing entry\n   * file or a default export that wasn't an array of GeneratorSpec.\n   */\n  failed: Array<{ source: string; reason: string }>\n}\n\n/** Shape of `package.json` we care about during discovery. */\ninterface PluginPackage {\n  name?: string\n  dependencies?: Record<string, string>\n  devDependencies?: Record<string, string>\n  peerDependencies?: Record<string, string>\n  kickjs?: {\n    generators?: string\n  }\n  keywords?: string[]\n}\n\n/**\n * Discover generator manifests shipped by every kickjs plugin in the\n * project's direct deps. Spec rationale: walking the\n * `node_modules/@scope/kickjs-name/` tree is one option, but reading\n * the project's own `package.json` and resolving each dep through\n * Node's module resolver gives:\n *\n *   1. Predictable scoping — only deps the project actually declared\n *      get scanned, no surprises from transitive packages\n *   2. pnpm `.pnpm` store compatibility — `createRequire().resolve()`\n *      handles the symlinked layout correctly\n *   3. Clear error attribution — the source package name is always\n *      known before the import happens\n *\n * The walk is shallow (direct deps only). Transitive plugins that want\n * to expose generators must be re-exported by a direct dep.\n *\n * Caches per-cwd inside one CLI invocation so a single `kick g` call\n * does the disk + import work exactly once even when multiple\n * generators dispatch through the same registry.\n */\nconst cache = new Map<string, Promise<DiscoveryResult>>()\n\nexport async function discoverPluginGenerators(cwd: string): Promise<DiscoveryResult> {\n  const cached = cache.get(cwd)\n  if (cached) return cached\n  const promise = doDiscover(cwd)\n  cache.set(cwd, promise)\n  return promise\n}\n\n/** Reset the cache — used by tests so repeated runs see fresh fixtures. */\nexport function resetGeneratorDiscoveryCache(): void {\n  cache.clear()\n}\n\nasync function doDiscover(cwd: string): Promise<DiscoveryResult> {\n  const projectPkgPath = resolve(cwd, 'package.json')\n  if (!existsSync(projectPkgPath)) {\n    return { generators: [], loaded: [], failed: [] }\n  }\n\n  const projectPkg = JSON.parse(await readFile(projectPkgPath, 'utf-8')) as PluginPackage\n  const depNames = collectDepNames(projectPkg)\n\n  const require = createRequire(resolve(cwd, 'package.json'))\n\n  const generators: DiscoveredGenerator[] = []\n  const loaded: string[] = []\n  const failed: Array<{ source: string; reason: string }> = []\n\n  for (const depName of depNames) {\n    let depPkgPath: string\n    try {\n      depPkgPath = require.resolve(`${depName}/package.json`)\n    } catch {\n      // Dep declared but not installed (or doesn't expose package.json\n      // via its export map). Skip silently — this is `kick g`, not\n      // `pnpm install`.\n      continue\n    }\n\n    let depPkg: PluginPackage\n    try {\n      depPkg = JSON.parse(await readFile(depPkgPath, 'utf-8')) as PluginPackage\n    } catch (err) {\n      failed.push({ source: depName, reason: `failed to parse package.json: ${err}` })\n      continue\n    }\n\n    if (!depPkg.kickjs?.generators) continue\n\n    const entryRel = depPkg.kickjs.generators\n    const entryAbs = resolve(dirname(depPkgPath), entryRel)\n    if (!existsSync(entryAbs)) {\n      failed.push({\n        source: depName,\n        reason: `kickjs.generators points to missing file: ${entryRel}`,\n      })\n      continue\n    }\n\n    let mod: unknown\n    try {\n      mod = await importManifest(entryAbs)\n    } catch (err) {\n      failed.push({ source: depName, reason: `failed to import manifest: ${err}` })\n      continue\n    }\n\n    const manifest = (mod as { default?: unknown }).default\n    if (!Array.isArray(manifest)) {\n      failed.push({\n        source: depName,\n        reason: `manifest's default export is not an array of GeneratorSpec`,\n      })\n      continue\n    }\n\n    for (const entry of manifest) {\n      if (!isGeneratorSpec(entry)) {\n        failed.push({\n          source: depName,\n          reason: `manifest entry is not a valid GeneratorSpec (missing name/files)`,\n        })\n        continue\n      }\n      generators.push({ source: depName, spec: entry })\n    }\n    loaded.push(depName)\n  }\n\n  return { generators, loaded, failed }\n}\n\nfunction collectDepNames(pkg: PluginPackage): string[] {\n  const set = new Set<string>()\n  for (const block of [pkg.dependencies, pkg.devDependencies, pkg.peerDependencies]) {\n    if (!block) continue\n    for (const name of Object.keys(block)) set.add(name)\n  }\n  return Array.from(set)\n}\n\nfunction isGeneratorSpec(entry: unknown): entry is GeneratorSpec {\n  if (!entry || typeof entry !== 'object') return false\n  const e = entry as Record<string, unknown>\n  return typeof e.name === 'string' && typeof e.files === 'function'\n}\n","import { writeFileSafe } from '../utils/fs'\nimport { buildGeneratorContext, resolveGeneratorPath } from './context'\nimport {\n  discoverPluginGenerators,\n  type DiscoveredGenerator,\n  type DiscoveryResult,\n} from './discover'\nimport type { GeneratorSpec } from './define'\n\nexport interface DispatchInput {\n  /** The generator name typed on the CLI (`kick g command Order` → `'command'`). */\n  generatorName: string\n  /** The first positional argument after the generator name. */\n  itemName: string\n  /** Remaining positional arguments. */\n  args?: string[]\n  /** Parsed flag map (booleans + values). */\n  flags?: Record<string, string | boolean>\n  /** Project context — usually `process.cwd()`. */\n  cwd?: string\n  /**\n   * Resolved project root. When omitted, `buildGeneratorContext` derives\n   * it from `cwd` via `findProjectRoot()`. Pass through when the caller\n   * has already resolved it (the CLI entry point does this once at\n   * startup) to avoid re-walking the filesystem on every generator call.\n   */\n  projectRoot?: string\n  /** Modules dir from `kick.config.ts`. */\n  modulesDir?: string\n  /** Whether the project enables auto-pluralization. */\n  pluralize?: boolean\n}\n\nexport interface DispatchResult {\n  /** Absolute paths of the files that were written. */\n  files: string[]\n  /** Which plugin owns the generator we ran. */\n  source: string\n}\n\n/**\n * Look up a plugin generator by name and run it. Returns `null` when\n * no plugin generator matches — callers can then fall through to the\n * built-in dispatch (module / scaffold / etc.).\n *\n * Resolution order:\n *   1. `additional` — generators sourced from `KickCliPlugin.generators`\n *      via `kick.config.ts > plugins[]`. Authoritative; the canonical\n *      path going forward.\n *   2. `package.json > kickjs.generators` discovery — first-match-wins\n *      in dependency declaration order. Deprecated path retained for\n *      packages that haven't migrated yet.\n *\n * Adopters with conflicts should rename the generator on their side or\n * pin one of the plugins to a different version.\n */\nexport async function tryDispatchPluginGenerator(\n  input: DispatchInput,\n  additional: readonly DiscoveredGenerator[] = [],\n): Promise<DispatchResult | null> {\n  const cwd = input.cwd ?? process.cwd()\n\n  const fromConfig = additional.find((g) => g.spec.name === input.generatorName)\n  if (fromConfig) {\n    return runGenerator(fromConfig.spec, fromConfig.source, input, cwd)\n  }\n\n  const discovery = await discoverPluginGenerators(cwd)\n  const match = findGenerator(discovery, input.generatorName)\n  if (!match) return null\n\n  return runGenerator(match.spec, match.source, input, cwd)\n}\n\n/**\n * Public helper for `kick g --list` — returns every plugin generator\n * the CLI knows about, merging config-supplied entries on top of the\n * package.json discovery result. Config entries always come first.\n */\nexport async function listPluginGenerators(\n  cwd: string,\n  additional: readonly DiscoveredGenerator[] = [],\n): Promise<DiscoveryResult> {\n  const discovered = await discoverPluginGenerators(cwd)\n  const configNames = new Set(additional.map((g) => g.spec.name))\n  const filteredDiscovered = discovered.generators.filter((g) => !configNames.has(g.spec.name))\n  return {\n    generators: [...additional, ...filteredDiscovered],\n    loaded: discovered.loaded,\n    failed: discovered.failed,\n  }\n}\n\nfunction findGenerator(discovery: DiscoveryResult, name: string): DiscoveredGenerator | undefined {\n  return discovery.generators.find((g) => g.spec.name === name)\n}\n\n/**\n * Invoke a {@link GeneratorSpec.files} factory with a fully-populated\n * {@link GeneratorContext}, write every returned file under the context's\n * cwd, and return the absolute paths along with the source plugin name.\n *\n * Threads `input.projectRoot` through to `buildGeneratorContext` so\n * callers that already resolved the project root (the CLI entry does\n * this once at startup) avoid a redundant filesystem walk. When omitted,\n * `buildGeneratorContext` derives `projectRoot` from `cwd` via\n * `findProjectRoot()` — keeping ad-hoc callers zero-config.\n */\nasync function runGenerator(\n  spec: GeneratorSpec,\n  source: string,\n  input: DispatchInput,\n  cwd: string,\n): Promise<DispatchResult> {\n  const ctx = buildGeneratorContext({\n    name: input.itemName,\n    args: input.args,\n    flags: input.flags,\n    modulesDir: input.modulesDir,\n    pluralize: input.pluralize,\n    cwd,\n    projectRoot: input.projectRoot,\n  })\n\n  const files = await spec.files(ctx)\n  const written: string[] = []\n\n  for (const file of files) {\n    const absPath = resolveGeneratorPath(ctx, file.path)\n    await writeFileSafe(absPath, file.content)\n    written.push(absPath)\n  }\n\n  return { files: written, source }\n}\n","import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'\nimport { dirname, join, relative, resolve } from 'node:path'\nimport type { Command } from 'commander'\nimport { loadKickConfig, type KickConfig } from '../config'\nimport { resolveAppRuntime, UPLOAD_DRIVERS, type AppRuntime } from './add'\nimport { colors } from '../utils/colors'\nimport { intro, outro, log } from '../utils/prompts'\n\n/**\n * `kick doctor` — pre-flight checks for a KickJS project's dev\n * environment. Detects common misconfigs before they bite, with an\n * actionable fix hint for each problem.\n *\n * Sibling command to `kick check --deploy`, which scans for production\n * readiness (JWT, CORS, helmet, etc.). Doctor is the dev-setup\n * counterpart — \"is my environment correctly wired?\"\n *\n * Extending: adopters can ship their own checks by exporting a\n * `doctor.checks` array from `kick.config.ts`. Each {@link DoctorCheck}\n * receives the same {@link DoctorContext} the built-ins use and\n * returns one or more {@link DoctorResult}s. The framework stays\n * ORM-agnostic — Prisma / Drizzle / Mongoose-specific checks belong\n * in their respective adapters or in adopter config, not in core.\n */\n\n// ── Public types ──────────────────────────────────────────────────────\n\nexport interface DoctorContext {\n  cwd: string\n  pkg: any | null\n  tsconfig: any | null\n  /**\n   * The project's HTTP runtime — from kick.config `runtime`, else sniffed from\n   * deps, else `express`. Lets engine-aware checks (engine peers, the upload\n   * multipart driver) validate against the right backend.\n   */\n  runtime: AppRuntime\n}\n\nexport interface DoctorResult {\n  /** Short label for the check (printed first). */\n  name: string\n  status: 'pass' | 'warn' | 'fail'\n  /** Optional extra context after the label (e.g. resolved version). */\n  message?: string\n  /** Multi-line actionable fix shown when status is `warn` or `fail`. */\n  fix?: string\n}\n\nexport type DoctorCheck = (\n  ctx: DoctorContext,\n) => DoctorResult | DoctorResult[] | null | Promise<DoctorResult | DoctorResult[] | null>\n\n/**\n * Shape of a doctor extension — the `doctor` block on `KickConfig`,\n * also the publishable unit that plugins and shared modules use to\n * ship a bundle of related checks.\n */\nexport interface DoctorExtension {\n  /** Extra checks merged after the built-ins. */\n  checks?: DoctorCheck[]\n}\n\n/**\n * Identity helper for adopters / plugins authoring a doctor extension.\n *\n * Provides type inference + autocomplete on the `checks` array without\n * requiring an explicit `: DoctorExtension` annotation. Mirrors the\n * `defineConfig` pattern.\n *\n * @example\n * ```ts\n * // doctor-checks/prisma.ts (shared across projects, or shipped as a\n * // standalone package)\n * import { defineDoctorExtension } from '@forinda/kickjs-cli'\n * import { existsSync } from 'node:fs'\n * import { join } from 'node:path'\n *\n * export const prismaDoctor = defineDoctorExtension({\n *   checks: [\n *     (ctx) => {\n *       if (!existsSync(join(ctx.cwd, 'prisma/schema.prisma'))) return null\n *       const generated = join(ctx.cwd, 'node_modules/@prisma/client/default.js')\n *       return existsSync(generated)\n *         ? { name: 'Prisma client generated', status: 'pass' }\n *         : { name: 'Prisma client generated', status: 'fail', fix: 'pnpm exec prisma generate' }\n *     },\n *   ],\n * })\n *\n * // kick.config.ts\n * import { defineConfig } from '@forinda/kickjs-cli'\n * import { prismaDoctor } from './doctor-checks/prisma'\n *\n * export default defineConfig({ doctor: prismaDoctor })\n * ```\n */\nexport function defineDoctorExtension(ext: DoctorExtension): DoctorExtension {\n  return ext\n}\n\n/**\n * Identity helper for a single doctor check. Pairs with\n * `defineDoctorExtension` when assembling an extension from separate\n * per-check files, and gives the same type-inference win for one-offs.\n *\n * @example\n * ```ts\n * import { defineDoctorCheck } from '@forinda/kickjs-cli'\n *\n * export const checkJwtSecretLength = defineDoctorCheck((ctx) => {\n *   const v = process.env.JWT_SECRET\n *   if (!v || v.length < 32) {\n *     return {\n *       name: 'JWT_SECRET ≥ 32 chars',\n *       status: 'warn',\n *       fix: 'Generate a strong secret: openssl rand -hex 32',\n *     }\n *   }\n *   return { name: 'JWT_SECRET ≥ 32 chars', status: 'pass' }\n * })\n * ```\n */\nexport function defineDoctorCheck(check: DoctorCheck): DoctorCheck {\n  return check\n}\n\n// ── File helpers ──────────────────────────────────────────────────────\n\nfunction safeReadJson(filepath: string): any | null {\n  try {\n    return JSON.parse(readFileSync(filepath, 'utf-8'))\n  } catch {\n    return null\n  }\n}\n\nfunction safeRead(filepath: string): string | null {\n  try {\n    return readFileSync(filepath, 'utf-8')\n  } catch {\n    return null\n  }\n}\n\n/**\n * Read tsconfig.json with `extends` followed one level. Most adopters\n * use a single config; for those that extend kickjs-cli's preset, we\n * pick up the inherited `compilerOptions`. Avoids pulling in `tsc` just\n * to resolve the chain.\n */\nfunction loadTsConfig(cwd: string): any | null {\n  const tsconfigPath = join(cwd, 'tsconfig.json')\n  const raw = safeRead(tsconfigPath)\n  if (!raw) return null\n  // tsconfig files often contain comments; strip them before parsing.\n  const stripped = raw.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '').replace(/\\/\\/.*$/gm, '')\n  let cfg: any\n  try {\n    cfg = JSON.parse(stripped)\n  } catch {\n    return null\n  }\n  if (typeof cfg?.extends === 'string') {\n    const extendsPath = resolveExtends(cwd, cfg.extends)\n    if (extendsPath) {\n      const parent = safeReadJson(extendsPath) ?? {}\n      cfg.compilerOptions = {\n        ...parent.compilerOptions,\n        ...cfg.compilerOptions,\n      }\n    }\n  }\n  return cfg\n}\n\nfunction resolveExtends(cwd: string, ext: string): string | null {\n  if (ext.startsWith('.')) {\n    const resolved = resolve(cwd, ext)\n    return existsSync(resolved) ? resolved : null\n  }\n  const mod = join(cwd, 'node_modules', ext)\n  if (existsSync(mod)) return mod\n  return null\n}\n\nfunction escapeRegExp(s: string): string {\n  return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\n// ── Individual checks ─────────────────────────────────────────────────\n\nconst MIN_NODE_MAJOR = 20\n\nexport function checkNodeVersion(): DoctorResult {\n  const v = process.version\n  const major = Number.parseInt(v.replace(/^v/, '').split('.')[0]!, 10)\n  if (Number.isNaN(major) || major < MIN_NODE_MAJOR) {\n    return {\n      name: 'Node version',\n      status: 'fail',\n      message: v,\n      fix: `KickJS requires Node ${MIN_NODE_MAJOR} or newer.\\nInstall a supported version via nvm / fnm / volta.`,\n    }\n  }\n  return { name: 'Node version', status: 'pass', message: v }\n}\n\nexport function checkKickJsInstalled(ctx: DoctorContext): DoctorResult {\n  if (!ctx.pkg) {\n    return { name: '@forinda/kickjs installed', status: 'warn', message: 'no package.json' }\n  }\n  const deps = {\n    ...ctx.pkg.dependencies,\n    ...ctx.pkg.peerDependencies,\n  }\n  if (!deps['@forinda/kickjs']) {\n    return {\n      name: '@forinda/kickjs installed',\n      status: 'fail',\n      fix: 'This directory does not look like a KickJS project — `@forinda/kickjs` is not in your package.json. Run `kick doctor` from the project root, or scaffold a fresh project with `kick new <name>`.',\n    }\n  }\n  return { name: '@forinda/kickjs installed', status: 'pass', message: deps['@forinda/kickjs'] }\n}\n\nexport function checkExpressInstalled(ctx: DoctorContext): DoctorResult | null {\n  if (!ctx.pkg) return null\n  const deps = {\n    ...ctx.pkg.dependencies,\n    ...ctx.pkg.peerDependencies,\n  }\n  if (deps['@forinda/kickjs'] && !deps.express) {\n    return {\n      name: 'express installed',\n      status: 'fail',\n      fix: '`@forinda/kickjs` declares `express` as a required peer dependency, but your package.json does not include it. Install: pnpm add express',\n    }\n  }\n  return deps.express ? { name: 'express installed', status: 'pass', message: deps.express } : null\n}\n\n/** Engine peers required by the configured non-Express runtime. */\nconst RUNTIME_PEERS: Record<AppRuntime, string[]> = {\n  express: [], // covered by checkExpressInstalled\n  fastify: ['fastify', '@fastify/middie'],\n  h3: ['h3'],\n}\n\n/**\n * The configured runtime's engine peers are installed. Express is checked by\n * {@link checkExpressInstalled}; this covers the Fastify / h3 runtimes, whose\n * peers are optional on `@forinda/kickjs` and so only required when chosen.\n */\nexport function checkRuntimeEngine(ctx: DoctorContext): DoctorResult | null {\n  if (!ctx.pkg || ctx.runtime === 'express') return null\n  const deps = {\n    ...ctx.pkg.dependencies,\n    ...ctx.pkg.peerDependencies,\n    ...ctx.pkg.devDependencies,\n  }\n  const missing = RUNTIME_PEERS[ctx.runtime].filter((p) => !deps[p])\n  const name = `runtime engine (${ctx.runtime})`\n  if (missing.length > 0) {\n    return {\n      name,\n      status: 'fail',\n      fix: `Resolved runtime '${ctx.runtime}' is missing engine peer(s): ${missing.join(', ')}.\\nInstall: pnpm add ${missing.join(' ')}`,\n    }\n  }\n  return { name, status: 'pass' }\n}\n\n/**\n * When the project actually uses file uploads (`@FileUpload` / the `upload`\n * middleware), the multipart driver for its runtime must be installed —\n * express → multer, fastify → @fastify/multipart, h3 → built-in (nothing).\n * Skips silently when no upload usage is detected, so non-upload apps aren't\n * nagged about a driver they don't need.\n */\nexport function checkUploadDriver(ctx: DoctorContext): DoctorResult | null {\n  if (!ctx.pkg || !srcUsesUpload(ctx.cwd)) return null\n  const driver = UPLOAD_DRIVERS[ctx.runtime]\n  const name = `upload driver (${ctx.runtime})`\n  // h3 parses multipart natively — there is no driver to require.\n  if (!driver.prod) return { name, status: 'pass', message: 'native multipart' }\n  const deps = {\n    ...ctx.pkg.dependencies,\n    ...ctx.pkg.peerDependencies,\n    ...ctx.pkg.devDependencies,\n  }\n  if (!deps[driver.prod]) {\n    return {\n      name,\n      status: 'fail',\n      fix: `This project uses file uploads on the '${ctx.runtime}' runtime, which needs '${driver.prod}'.\\nInstall it: kick add upload (or pnpm add ${driver.prod})`,\n    }\n  }\n  return { name, status: 'pass', message: driver.prod }\n}\n\nconst MAX_UPLOAD_SCAN_FILES = 2000\n\n/** Bounded walk of src/ looking for @FileUpload / upload.single|array|none usage. */\nfunction srcUsesUpload(cwd: string): boolean {\n  const srcDir = join(cwd, 'src')\n  if (!existsSync(srcDir)) return false\n  const pattern = /@FileUpload\\b|\\bupload\\.(single|array|none)\\s*\\(/\n  const stack = [srcDir]\n  let visited = 0\n  while (stack.length > 0 && visited < MAX_UPLOAD_SCAN_FILES) {\n    const current = stack.pop()!\n    let entries\n    try {\n      entries = readdirSync(current, { withFileTypes: true })\n    } catch {\n      continue\n    }\n    for (const entry of entries) {\n      if (visited >= MAX_UPLOAD_SCAN_FILES) break\n      const full = join(current, entry.name)\n      if (entry.isDirectory()) {\n        if (entry.name !== 'node_modules') stack.push(full)\n        continue\n      }\n      if (!/\\.(ts|tsx|mts|cts)$/.test(entry.name)) continue\n      visited++\n      if (pattern.test(safeRead(full) ?? '')) return true\n    }\n  }\n  return false\n}\n\nexport function checkReflectMetadata(ctx: DoctorContext): DoctorResult {\n  if (!ctx.pkg)\n    return { name: 'reflect-metadata installed', status: 'warn', message: 'no package.json' }\n  const deps = {\n    ...ctx.pkg.dependencies,\n    ...ctx.pkg.peerDependencies,\n    ...ctx.pkg.devDependencies,\n  }\n  if (!deps['reflect-metadata']) {\n    return {\n      name: 'reflect-metadata installed',\n      status: 'fail',\n      fix: `KickJS decorators require the reflect-metadata polyfill.\\nInstall it: pnpm add reflect-metadata\\nThen import it at the top of src/index.ts:\\n\\n  import 'reflect-metadata'\\n  // ... rest of bootstrap`,\n    }\n  }\n  return { name: 'reflect-metadata installed', status: 'pass', message: deps['reflect-metadata'] }\n}\n\nexport function checkDecoratorTsConfig(ctx: DoctorContext): DoctorResult[] {\n  if (!ctx.tsconfig) {\n    return [\n      {\n        name: 'tsconfig.json present',\n        status: 'fail',\n        fix: 'Create a tsconfig.json with `experimentalDecorators: true` and `emitDecoratorMetadata: true`. `kick new` scaffolds one automatically.',\n      },\n    ]\n  }\n  const co = ctx.tsconfig.compilerOptions ?? {}\n  const results: DoctorResult[] = []\n  results.push(\n    co.experimentalDecorators === true\n      ? { name: 'tsconfig: experimentalDecorators', status: 'pass' }\n      : {\n          name: 'tsconfig: experimentalDecorators',\n          status: 'fail',\n          fix: 'Add `\"experimentalDecorators\": true` to compilerOptions in tsconfig.json. Without it, @Service / @Controller / @Get etc. don\\'t register any metadata at compile time.',\n        },\n  )\n  results.push(\n    co.emitDecoratorMetadata === true\n      ? { name: 'tsconfig: emitDecoratorMetadata', status: 'pass' }\n      : {\n          name: 'tsconfig: emitDecoratorMetadata',\n          status: 'fail',\n          fix: 'Add `\"emitDecoratorMetadata\": true` to compilerOptions in tsconfig.json. The DI container uses this metadata for constructor-parameter injection.',\n        },\n  )\n  return results\n}\n\n/**\n * The canonical \"you forgot to wire env\" footgun: an env-init file\n * (e.g. `src/env.ts`, `src/config/env.ts`, `src/config/index.ts`)\n * calls `loadEnv(envSchema)` as a side effect, but the app entry\n * (`src/index.ts` / `src/main.ts`) doesn't import it. Result:\n * `ConfigService.get('X')` returns undefined while `@Value('X')`\n * works via process.env fallback, so adopters get half-broken config\n * without seeing an error.\n *\n * Detection walks the common env-file locations, identifies the ones\n * that actually call `loadEnv(`, then verifies the app entry imports\n * one of them (via relative path or `@/` alias) BEFORE `bootstrap(`.\n */\nexport function checkEnvWiring(ctx: DoctorContext): DoctorResult | null {\n  const envCandidates = [\n    'src/env.ts',\n    'src/env/index.ts',\n    'src/config/env.ts',\n    'src/config/index.ts',\n  ]\n  const envFiles = envCandidates\n    .map((p) => join(ctx.cwd, p))\n    .filter((p) => existsSync(p))\n    .filter((p) => /\\bloadEnv\\s*\\(/.test(safeRead(p) ?? ''))\n\n  if (envFiles.length === 0) return null\n\n  const indexPath = ['src/index.ts', 'src/main.ts']\n    .map((p) => join(ctx.cwd, p))\n    .find((p) => existsSync(p))\n  if (!indexPath) {\n    return {\n      name: 'env wiring',\n      status: 'warn',\n      message: 'env-init file exists but no src/index.ts or src/main.ts found',\n    }\n  }\n  const indexContent = safeRead(indexPath) ?? ''\n  const indexDir = dirname(indexPath)\n\n  // Build the set of import specifiers that would wire any of these\n  // env files — relative paths (`./env`, `./config/env`, …) and the\n  // `@/` alias variant (`@/env`, `@/config/env`, …). For each file we\n  // accept both the with-`/index` suffix and the bare-directory form,\n  // since both resolve to the same module under TypeScript.\n  const importSpecs: string[] = []\n  for (const envFile of envFiles) {\n    const relPath = relative(indexDir, envFile).replace(/\\\\/g, '/').replace(/\\.ts$/, '')\n    const relImport = relPath.startsWith('.') ? relPath : './' + relPath\n    const relImportNoIndex = relImport.replace(/\\/index$/, '')\n    importSpecs.push(relImport, relImportNoIndex)\n\n    // `@/` is the standard alias the scaffold and most adopters use;\n    // it points at `src/`. Derive the @/-prefixed path from the file's\n    // location under src/.\n    const srcRel = envFile.replace(/\\\\/g, '/').match(/\\/src\\/(.+?)(?:\\.ts)?$/)\n    if (srcRel) {\n      const aliasImport = '@/' + srcRel[1]\n      const aliasNoIndex = aliasImport.replace(/\\/index$/, '')\n      importSpecs.push(aliasImport, aliasNoIndex)\n    }\n  }\n\n  let earliestImportIdx = -1\n  for (const spec of new Set(importSpecs)) {\n    const re = new RegExp(`^import\\\\s+(?:.*?from\\\\s+)?['\"]${escapeRegExp(spec)}['\"]`, 'm')\n    const m = indexContent.match(re)\n    if (m && m.index !== undefined) {\n      if (earliestImportIdx === -1 || m.index < earliestImportIdx) {\n        earliestImportIdx = m.index\n      }\n    }\n  }\n\n  const bootstrapIdx = indexContent.search(/\\bbootstrap\\s*\\(/)\n  const sample = envFiles.map((p) => relative(ctx.cwd, p).replace(/\\\\/g, '/')).join(', ')\n\n  if (earliestImportIdx === -1) {\n    return {\n      name: 'env wiring',\n      status: 'fail',\n      message: sample,\n      fix: `An env-init file (${sample}) calls \\`loadEnv(...)\\` but \\`${relative(ctx.cwd, indexPath).replace(/\\\\/g, '/')}\\` doesn't import it.\\nWithout this, ConfigService.get('X') returns undefined while @Value('X') works via process.env fallback — a half-broken config you won't notice until something is missing.\\n\\nFix: add a side-effect import at the top of ${relative(ctx.cwd, indexPath).replace(/\\\\/g, '/')} (above bootstrap()), pointing at one of the detected files. For example:\\n\\n  import './env'\\n  // or\\n  import './config'\\n  // or, with the @/ alias:\\n  import '@/config/env'`,\n    }\n  }\n  if (bootstrapIdx !== -1 && earliestImportIdx > bootstrapIdx) {\n    return {\n      name: 'env wiring',\n      status: 'warn',\n      message: 'env-init imported AFTER bootstrap() — should be before',\n      fix: `Move the env import above the bootstrap() call so the schema runs before any service reads from ConfigService.`,\n    }\n  }\n  return { name: 'env wiring', status: 'pass' }\n}\n\n/**\n * Find the newest file mtime under a directory tree, recursively.\n * Returns `0` when the tree is empty or unreadable. Walks at most\n * {@link MAX_TYPEGEN_FILES} entries to bound the cost on large\n * generated trees.\n *\n * Necessary because the directory's own `mtimeMs` does not update\n * when existing files inside are rewritten — `kick typegen` can run\n * successfully and the directory stat still looks stale. The newest\n * file mtime is the honest measure.\n */\nfunction newestFileMtime(dir: string, budget = MAX_TYPEGEN_FILES): number {\n  let newest = 0\n  let visited = 0\n  const stack = [dir]\n  while (stack.length > 0 && visited < budget) {\n    const current = stack.pop()!\n    let entries\n    try {\n      entries = readdirSync(current, { withFileTypes: true })\n    } catch {\n      continue\n    }\n    for (const entry of entries) {\n      if (visited >= budget) break\n      visited++\n      const full = join(current, entry.name)\n      if (entry.isDirectory()) {\n        stack.push(full)\n        continue\n      }\n      try {\n        const m = statSync(full).mtimeMs\n        if (m > newest) newest = m\n      } catch {\n        // skip unreadable files\n      }\n    }\n  }\n  return newest\n}\n\nconst MAX_TYPEGEN_FILES = 2000\n\nexport function checkTypegenFreshness(ctx: DoctorContext): DoctorResult | null {\n  const typegenDir = join(ctx.cwd, '.kickjs', 'types')\n  if (!existsSync(typegenDir)) return null\n  const newest = newestFileMtime(typegenDir)\n  if (newest === 0) return null\n  const ageMs = Date.now() - newest\n  const ageMin = Math.floor(ageMs / 60_000)\n  if (ageMin > 60) {\n    return {\n      name: 'typegen freshness',\n      status: 'warn',\n      message: `last updated ${ageMin} minutes ago`,\n      fix: 'Re-run `kick typegen` (or `kick dev`, which runs it on every reload) so generated types match the current code.',\n    }\n  }\n  return {\n    name: 'typegen freshness',\n    status: 'pass',\n    message: ageMin === 0 ? 'just now' : `${ageMin}m ago`,\n  }\n}\n\n// ── Runner ────────────────────────────────────────────────────────────\n\nconst BUILT_IN_CHECKS: DoctorCheck[] = [\n  () => checkNodeVersion(),\n  checkKickJsInstalled,\n  checkExpressInstalled,\n  checkRuntimeEngine,\n  checkUploadDriver,\n  checkReflectMetadata,\n  checkDecoratorTsConfig,\n  checkEnvWiring,\n  checkTypegenFreshness,\n]\n\nexport async function runChecks(\n  cwd: string,\n  options: { extraChecks?: DoctorCheck[]; runtime?: AppRuntime } = {},\n): Promise<DoctorResult[]> {\n  const ctx: DoctorContext = {\n    cwd,\n    pkg: safeReadJson(join(cwd, 'package.json')),\n    tsconfig: loadTsConfig(cwd),\n    runtime: options.runtime ?? 'express',\n  }\n  const checks = [...BUILT_IN_CHECKS, ...(options.extraChecks ?? [])]\n  const out: DoctorResult[] = []\n  for (const check of checks) {\n    // Per-check try/catch so one buggy extension can't abort the whole\n    // report. A throwing check produces a synthetic `fail` result with\n    // the error message; the loop continues to the next check.\n    let r: DoctorResult | DoctorResult[] | null\n    try {\n      r = await check(ctx)\n    } catch (err) {\n      out.push({\n        name: check.name || 'doctor check',\n        status: 'fail',\n        message: err instanceof Error ? err.message : String(err),\n      })\n      continue\n    }\n    if (r == null) continue\n    if (Array.isArray(r)) out.push(...r)\n    else out.push(r)\n  }\n  return out\n}\n\n// ── Output ────────────────────────────────────────────────────────────\n\nfunction statusTag(status: DoctorResult['status']): string {\n  switch (status) {\n    case 'pass':\n      return colors.green('✔')\n    case 'warn':\n      return colors.yellow('⚠')\n    case 'fail':\n      return colors.red('✖')\n  }\n}\n\nfunction formatResult(r: DoctorResult): string {\n  const tag = statusTag(r.status)\n  const tail = r.message ? `  ${colors.dim(`(${r.message})`)}` : ''\n  return `${tag}  ${r.name}${tail}`\n}\n\nfunction formatFix(fix: string): string {\n  return fix\n    .split('\\n')\n    .map((line) => `   ${colors.dim('→')} ${line}`)\n    .join('\\n')\n}\n\n// ── Command registration ──────────────────────────────────────────────\n\nfunction extractDoctorChecks(config: KickConfig | null): DoctorCheck[] {\n  return config?.doctor?.checks ?? []\n}\n\nexport function registerDoctorCommand(program: Command): void {\n  program\n    .command('doctor')\n    .description('Pre-flight checks for your KickJS project (dev environment health)')\n    .action(async () => {\n      const cwd = process.cwd()\n      const config = await loadKickConfig(cwd)\n      const extraChecks = extractDoctorChecks(config)\n      const runtime = await resolveAppRuntime(cwd)\n\n      intro('KickJS Doctor')\n\n      const results = await runChecks(cwd, { extraChecks, runtime })\n\n      for (const r of results) {\n        log.message(formatResult(r))\n        if (r.fix && r.status !== 'pass') {\n          log.message(formatFix(r.fix))\n        }\n      }\n\n      const passed = results.filter((r) => r.status === 'pass').length\n      const warns = results.filter((r) => r.status === 'warn').length\n      const fails = results.filter((r) => r.status === 'fail').length\n\n      const passText = colors.green(`${passed} passed`)\n      const warnText =\n        warns > 0 ? colors.yellow(`${warns} warning${warns === 1 ? '' : 's'}`) : `${warns} warnings`\n      const failText =\n        fails > 0 ? colors.red(`${fails} error${fails === 1 ? '' : 's'}`) : `${fails} errors`\n      const summary = [passText, warnText, failText].join(', ')\n\n      if (fails > 0) {\n        outro(`${summary} — fix the errors above before running the app`)\n        process.exit(1)\n      } else if (warns > 0) {\n        outro(`${summary} — review the warnings`)\n      } else {\n        outro(colors.green(`${summary} — your environment looks good`))\n      }\n    })\n}\n"],"mappings":"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"}