{"version":3,"file":"project-CdPZ9hA0.mjs","names":[],"sources":["../src/generators/templates/project-app.ts","../src/utils/shell.ts","../src/generators/templates/project-config.ts","../src/commands/add.ts","../src/generators/project.ts"],"sourcesContent":["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  /**\n   * When set, wire `SpaAdapter` at this `clientDir`. Used by the fullstack\n   * template so `web/`'s build is served from the API's origin in\n   * production. The adapter no-ops while the directory does not exist, so a\n   * dev run (where the SPA is served by Vite) is unaffected.\n   */\n  spaClientDir?: string,\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      if (spaClientDir) {\n        imports.push(`import { SpaAdapter } from '@forinda/kickjs/spa'`)\n        // JSON.stringify, not a quoted template hole: this is arbitrary\n        // caller-supplied path text being written into a TypeScript file, and\n        // a quote, backslash, or newline in it would either break the emitted\n        // module or quietly change the path it resolves. The raw value stays\n        // out of the comment for the same reason.\n        adapters.push(\n          `    // Serves the built frontend from this origin in production.\\n` +\n            `    // Inert until the client build exists, so \\`kick dev\\` (where Vite\\n` +\n            `    // serves the client and proxies /api here) is unaffected.\\n` +\n            `    SpaAdapter({ clientDir: ${JSON.stringify(spaClientDir)} }),`,\n        )\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 * `loadEnvFromSchema(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  // Return-value handlers: the runtime sends the returned payload as\n  // 200 json, and \\`kick typegen\\` infers the response type into\n  // \\`KickRoutes.Api\\` — which is what makes the typed client\n  // (@forinda/kickjs-client) end-to-end type-safe.\n  @Get('/')\n  index(_ctx: Ctx<KickRoutes.HelloController['index']>) {\n    return this.helloService.greet('World')\n  }\n\n  @Get('/health')\n  health(_ctx: Ctx<KickRoutes.HelloController['health']>) {\n    return 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 { execFileSync, execSync, spawnSync } from 'node:child_process'\n\n/**\n * Characters an argument may not contain when it has to travel through\n * `cmd.exe`.\n *\n * The first group is shell syntax — `cmd.exe` would interpret these rather\n * than pass them through. The trailing `\\\\` is different in kind: a backslash\n * is not shell syntax, but Windows command-line quoting mangles it. Node's\n * argv encoder doubles trailing backslashes, and a backslash immediately\n * before a closing quote escapes that quote, so a single argument silently\n * splits in two:\n *\n *   ['C:\\\\some path\\\\']  →  cmd receives  ['\"C:\\\\some', 'path\\\\\"']\n *   ['no-space\\\\']       →  cmd receives  ['no-space\\\\\\\\']\n *\n * Correct escaping is possible but fiddly, and no caller in this CLI needs it\n * — arguments here are package names, dist-tags, subcommands and flags, and\n * working directories travel via the `cwd` option rather than as arguments.\n * So a backslash is rejected outright: a loud `null` beats a silently\n * corrupted argument, which is the exact failure mode this module exists to\n * eliminate.\n */\nconst CMD_UNSAFE = /[&|<>^\"'`(){}[\\];!%\\r\\n\\\\]/\n\n/**\n * Build the `[file, args]` pair to hand to `execFileSync`, routing through\n * `cmd.exe` on Windows so `.cmd` shims are launchable.\n *\n * On Windows, `npm` / `pnpm` / `yarn` / `bun` are `.cmd` batch shims, not\n * `.exe`s, and `execFileSync` cannot launch either spelling:\n *\n *   - `execFileSync('npm', …)`     → ENOENT  (there is no `npm.exe` on PATH)\n *   - `execFileSync('npm.cmd', …)` → EINVAL  (Node >= 18.20 / 20.12 refuses to\n *                                             spawn batch files without a\n *                                             shell — CVE-2024-27980)\n *\n * Both failures are silent wherever the caller swallows the error, so the\n * command looks like it \"returned nothing\" rather than \"never ran\".\n *\n * `/d` skips AutoRun registry commands, `/s` makes cmd treat everything after\n * `/c` as one verbatim string (it strips only the outer quote pair Node adds).\n * Returns `null` when an argument is unsafe to pass through — refusing to run\n * beats running something the shell rewrote.\n *\n * `platform` is injectable so both branches are unit-testable from any host\n * OS; production callers use the default. It is read per call rather than\n * captured at import time for the same reason.\n */\nexport function shellSafeInvocation(\n  file: string,\n  args: string[],\n  platform: NodeJS.Platform = process.platform,\n): [string, string[]] | null {\n  if (platform !== 'win32') return [file, args]\n  if (CMD_UNSAFE.test(file) || args.some((a) => CMD_UNSAFE.test(a))) return null\n  const command = [file, ...args].map((a) => (a.includes(' ') ? `\"${a}\"` : a)).join(' ')\n  return [process.env.ComSpec || 'cmd.exe', ['/d', '/s', '/c', command]]\n}\n\n/**\n * Run a command and capture its trimmed stdout, cross-platform.\n *\n * Returns `null` if the command is missing, exits non-zero, times out, or\n * carries arguments unsafe to pass through `cmd.exe`. Callers treat `null` as\n * \"unknown\" and fall back — the point of this helper is that a Windows `.cmd`\n * shim no longer masquerades as a failed command.\n */\nexport function captureCommand(\n  file: string,\n  args: string[],\n  opts: { timeout?: number; cwd?: string } = {},\n): string | null {\n  const invocation = shellSafeInvocation(file, args)\n  if (!invocation) return null\n  try {\n    const out = execFileSync(invocation[0], invocation[1], {\n      encoding: 'utf-8',\n      timeout: opts.timeout ?? 5000,\n      cwd: opts.cwd,\n      stdio: ['ignore', 'pipe', 'ignore'],\n      windowsHide: true,\n    })\n    const trimmed = out.toString().trim()\n    return trimmed || null\n  } catch {\n    return null\n  }\n}\n\n/**\n * Run a command with inherited stdio, cross-platform. Throws on failure so\n * callers can decide whether a missing package manager is fatal.\n */\nexport function runCommand(file: string, args: string[], opts: { cwd?: string } = {}): void {\n  const invocation = shellSafeInvocation(file, args)\n  if (!invocation) throw new Error(`Refusing to run '${file}': unsafe arguments`)\n  execFileSync(invocation[0], invocation[1], {\n    cwd: opts.cwd,\n    stdio: 'inherit',\n    windowsHide: true,\n  })\n}\n\n/**\n * Run a shell command synchronously, printing output.\n *\n * On Windows, `execSync` spawns via `cmd.exe` by default, which means\n * POSIX-style inline env prefixes like `FOO=bar node app.js` do NOT work.\n * Callers that need environment variables should pass them in the `env`\n * option instead of prepending them to the command string — see\n * `runNodeWithEnv` for the cross-platform helper that avoids a shell\n * entirely.\n */\nexport function runShellCommand(command: string, cwd?: string, env?: NodeJS.ProcessEnv): void {\n  execSync(command, {\n    cwd,\n    stdio: 'inherit',\n    env: env ? { ...process.env, ...env } : process.env,\n  })\n}\n\n/**\n * Cross-platform way to launch a Node.js process with a set of\n * environment variables. Uses `spawnSync` with an argument array so no\n * shell is involved — the `VAR=value node ...` POSIX prefix syntax that\n * `runShellCommand` relied on breaks on cmd.exe and PowerShell.\n */\nexport function runNodeWithEnv(entry: string, env: NodeJS.ProcessEnv, cwd?: string): void {\n  const result = spawnSync(process.execPath, [entry], {\n    cwd,\n    stdio: 'inherit',\n    env: { ...process.env, ...env },\n  })\n  if (result.status !== 0) {\n    process.exit(result.status ?? 1)\n  }\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        // The generated AGENTS.md and the `write-controller-test` skill both\n        // tell you to test with `createTestApp` + supertest. Shipping those\n        // instructions without the packages means the first test a reader\n        // writes fails on a missing import.\n        '@forinda/kickjs-testing': take(versions, '@forinda/kickjs-testing'),\n        '@forinda/kickjs-vite': take(versions, '@forinda/kickjs-vite'),\n        '@types/supertest': '^7.2.1',\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        supertest: '^7.2.2',\n        vitest: '^4.1.2',\n        typescript: '^7.0.2',\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 { fileURLToPath } from 'node:url'\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      '@': fileURLToPath(new URL('./src', import.meta.url)),\n    },\n  },\n  build: {\n    target: 'node20',\n    ssr: true,\n    outDir: 'dist',\n    sourcemap: true,\n    rollupOptions: {\n      input: fileURLToPath(new URL('./src/index.ts', import.meta.url)),\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\n# Personal machine overrides. \\`.env.test\\` itself is COMMITTED — it is the\n# suite's shared, reviewable environment — but \\`*.local\\` never is.\n*.local\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/**\n * Generate `.env.test` — the environment the test suite runs against.\n *\n * Under a test run KickJS reads this file INSTEAD of `.env` (no layering,\n * no fallback), so scaffolding it is what makes a new project isolated by\n * default rather than inheriting the developer's environment.\n *\n * Deliberately NOT a copy of `.env.example`. The point of the file is that\n * a var it omits is *missing* rather than quietly inherited, so the suite\n * fails loudly on something it forgot to declare. Copying every key back\n * in would rebuild the exact trap this closes.\n *\n * `PORT=0` asks the OS for a free port, so a test run cannot collide with\n * a dev server already on 3000.\n */\nexport function generateEnvTest(): string {\n  return `# Read INSTEAD of .env when NODE_ENV=test (or under vitest).\n# No fallback to .env — declare here everything the suite needs, so a\n# missing var fails the run instead of silently resolving to your dev value.\n#\n# Keep real endpoints and credentials OUT of this file. Point at test\n# doubles or throwaway containers; anything committed here is shared with\n# everyone who clones the repo.\nNODE_ENV=test\nPORT=0\nLOG_LEVEL=silent\n`\n}\n\n/** Generate vitest.config.ts for test configuration */\nexport function generateVitestConfig(): string {\n  return `import { defineConfig, mergeConfig } from 'vitest/config'\nimport viteConfig from './vite.config.ts'\n\n// A \\`vitest.config.ts\\` OVERRIDES \\`vite.config.ts\\` outright — vitest does not\n// merge the two, and it never reads tsconfig \\`paths\\`. Restating settings here\n// would mean the \\`@\\` alias lives in three files and drifts in two of them, so\n// merge the real config instead: the alias, plugins, and ssr externals all come\n// from one place.\nexport default mergeConfig(\n  viteConfig,\n  defineConfig({\n    test: {\n      globals: true,\n      environment: 'node',\n      include: ['src/**/*.test.ts'],\n    },\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 { execSync } from 'node:child_process'\nimport { readFileSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\nimport { writeFileSafe } from '../utils/fs'\nimport { captureCommand } from '../utils/shell'\nimport {\n  generatePackageJson,\n  generateViteConfig,\n  generateTsConfig,\n  generatePrettierConfig,\n  generateEditorConfig,\n  generateGitIgnore,\n  generateGitAttributes,\n  generateEnv,\n  generateEnvExample,\n  generateEnvTest,\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  '@forinda/kickjs-client',\n] as const\n\n/**\n * Resolve the latest published version of every sibling package via\n * `npm view <name> version` (through `captureCommand`, which routes\n * around Windows' `.cmd` shims — see utils/shell.ts). Each query has a\n * short timeout; failures fall back to the CLI's own version with a `^`\n * prefix so the scaffold stays usable offline.\n */\nexport async function resolveSiblingVersions(): Promise<Record<string, string>> {\n  const results = await Promise.all(\n    SIBLING_PACKAGES.map(async (name) => {\n      // Network failure / package not yet published / npm unavailable\n      // all surface as null → fall back to the CLI's own version.\n      const out = captureCommand('npm', ['view', name, 'version'])\n      if (out && /^\\d+\\.\\d+\\.\\d+/.test(out)) {\n        return [name, `^${out}`] as const\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  const out = captureCommand('npm', ['view', `${name}@${tag}`, 'version'])\n  return out && /^\\d+\\.\\d+\\.\\d+/.test(out) ? out : null\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  const out = captureCommand('npm', ['view', `${name}@${tag}`, 'exports', '--json'])\n  if (!out) return false\n  try {\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  /** Wire `SpaAdapter` at this clientDir (fullstack template). */\n  spaClientDir?: string\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  // `.env.test` is read INSTEAD of `.env` under a test run, so scaffolding\n  // it is what makes a new project isolated by default. Without it the\n  // generated app ships the exact shape `kick doctor` warns about — a\n  // `.env` plus a test runner — and its first test run prints the backfill\n  // warning rather than being isolated.\n  await writeFileSafe(join(dir, '.env.test'), generateEnvTest())\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, options.spaClientDir),\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"],"mappings":"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"}