@forinda/kickjs-cli 6.9.0 → 6.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-docs-BEaN-yVq.mjs → agent-docs-B249TRF6.mjs} +2 -2
- package/dist/{agent-docs-NyyqHAxw.mjs → agent-docs-C5wwicRH.mjs} +3 -3
- package/dist/{agent-docs-NyyqHAxw.mjs.map → agent-docs-C5wwicRH.mjs.map} +1 -1
- package/dist/{build-CNy9rla8.mjs → build-CWHh0hVP.mjs} +3 -3
- package/dist/{build-CNy9rla8.mjs.map → build-CWHh0hVP.mjs.map} +1 -1
- package/dist/{build-DBdGEMiZ.mjs → build-HlXY_TeD.mjs} +2 -2
- package/dist/{builtins-DR3wYkm4.mjs → builtins-DCjV6a7i.mjs} +121 -121
- package/dist/{builtins-epL6Z9Me.mjs → builtins-DNYHt9aW.mjs} +2 -2
- package/dist/cli.mjs +2 -2
- package/dist/{config-BnGHE669.mjs → config-BkoZPh4q.mjs} +3 -3
- package/dist/{config-BnGHE669.mjs.map → config-BkoZPh4q.mjs.map} +1 -1
- package/dist/{config-BQy8iVib.mjs → config-mzx_v7G3.mjs} +2 -2
- package/dist/{doctor-26f-Bu4P.mjs → doctor-b7agdFBr.mjs} +4 -4
- package/dist/{doctor-26f-Bu4P.mjs.map → doctor-b7agdFBr.mjs.map} +1 -1
- package/dist/{fullstack-DUPLtANA.mjs → fullstack-BLUIrHET.mjs} +12 -12
- package/dist/{fullstack-CeSmhGE2.mjs → fullstack-sXqerW2t.mjs} +13 -13
- package/dist/fullstack-sXqerW2t.mjs.map +1 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{plugin-C3PeTJQb.mjs → plugin-CSpzl41q.mjs} +2 -2
- package/dist/{plugin-RBStrEDQ.mjs → plugin-DKCkz86s.mjs} +3 -3
- package/dist/{plugin-RBStrEDQ.mjs.map → plugin-DKCkz86s.mjs.map} +1 -1
- package/dist/{project-DxcX4ryE.mjs → project-BN_7MhLe.mjs} +21 -21
- package/dist/project-BN_7MhLe.mjs.map +1 -0
- package/dist/{project-Op2Qt1bv.mjs → project-DDhIi-9v.mjs} +20 -20
- package/dist/{project-docs-uEIleRls.mjs → project-docs-B3pdPjqd.mjs} +1 -1
- package/dist/{project-docs-BQ022LVW.mjs → project-docs-nlJ0u0U1.mjs} +2 -2
- package/dist/{project-docs-BQ022LVW.mjs.map → project-docs-nlJ0u0U1.mjs.map} +1 -1
- package/dist/{project-root-CtnL9FBb.mjs → project-root-DSNzsiYI.mjs} +2 -2
- package/dist/{project-root-BifjB5PL.mjs → project-root-DrwinO6A.mjs} +3 -3
- package/dist/{project-root-BifjB5PL.mjs.map → project-root-DrwinO6A.mjs.map} +1 -1
- package/dist/{prompts-j1nmMgAf.mjs → prompts-CmCfbzYN.mjs} +2 -2
- package/dist/{prompts-j1nmMgAf.mjs.map → prompts-CmCfbzYN.mjs.map} +1 -1
- package/dist/{rolldown-runtime-DOk7ha8c.mjs → rolldown-runtime-DJeMLCTO.mjs} +1 -1
- package/dist/{run-plugins-BouWvZvo.mjs → run-plugins-De8oWOq0.mjs} +45 -45
- package/dist/run-plugins-De8oWOq0.mjs.map +1 -0
- package/dist/{typegen-b-Siu3FR.mjs → typegen-CbMLPc5z.mjs} +4 -4
- package/dist/{typegen-DRSOapGb.mjs → typegen-DJlB47Fw.mjs} +5 -5
- package/dist/{typegen-DRSOapGb.mjs.map → typegen-DJlB47Fw.mjs.map} +1 -1
- package/dist/{types-DSOcCoe_.mjs → types-BpdxjqT6.mjs} +1 -1
- package/package.json +8 -8
- package/dist/fullstack-CeSmhGE2.mjs.map +0 -1
- package/dist/project-DxcX4ryE.mjs.map +0 -1
- package/dist/run-plugins-BouWvZvo.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-BN_7MhLe.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): 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 // 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 '@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: '^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 { 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 { 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 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}\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"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v6.9.
|
|
2
|
+
* @forinda/kickjs-cli v6.9.2
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import{r as e,t}from"./config-
|
|
11
|
+
import{r as e,t}from"./config-mzx_v7G3.mjs";import{l as n,o as r}from"./project-docs-B3pdPjqd.mjs";import{existsSync as i,readFileSync as a}from"node:fs";import{dirname as o,join as s,resolve as c}from"node:path";import{fileURLToPath as l}from"node:url";import{execFileSync as u,execSync as d,spawnSync as f}from"node:child_process";const p=/[&|<>^"'`(){}[\];!%\r\n\\]/;function m(e,t,n=process.platform){if(n!==`win32`)return[e,t];if(p.test(e)||t.some(e=>p.test(e)))return null;let r=[e,...t].map(e=>e.includes(` `)?`"${e}"`:e).join(` `);return[process.env.ComSpec||`cmd.exe`,[`/d`,`/s`,`/c`,r]]}function h(e,t,n={}){let r=m(e,t);if(!r)return null;try{return u(r[0],r[1],{encoding:`utf-8`,timeout:n.timeout??5e3,cwd:n.cwd,stdio:[`ignore`,`pipe`,`ignore`],windowsHide:!0}).toString().trim()||null}catch{return null}}function g(e,t,n={}){let r=m(e,t);if(!r)throw Error(`Refusing to run '${e}': unsafe arguments`);u(r[0],r[1],{cwd:n.cwd,stdio:`inherit`,windowsHide:!0})}function _(e,t,n){d(e,{cwd:t,stdio:`inherit`,env:n?{...process.env,...n}:process.env})}function v(e,t,n){let r=f(process.execPath,[e],{cwd:n,stdio:`inherit`,env:{...process.env,...t}});r.status!==0&&process.exit(r.status??1)}const y={swagger:`@forinda/kickjs-swagger`,ws:`@forinda/kickjs-ws`,queue:`@forinda/kickjs-queue`,devtools:`@forinda/kickjs-devtools`},b={zod:{name:`zod`,range:`^4.3.6`},valibot:{name:`valibot`,range:`^1.4.1`},yup:{name:`yup`,range:`^1.7.1`}};function x(e,t){let n=e[t];if(!n)throw Error(`generatePackageJson: missing resolved version for ${t}. Add it to SIBLING_PACKAGES in generators/project.ts.`);return n}function S(e,t,n,r=[],i=`zod`,a=`express`){let o=b[i],s={"@forinda/kickjs":x(n,`@forinda/kickjs`),"@forinda/kickjs-schema":x(n,`@forinda/kickjs-schema`),dotenv:`^17.3.1`,"reflect-metadata":`^0.2.2`,[o.name]:o.range};a===`express`?s.express=`^5.1.0`:a===`fastify`?(s.fastify=`^5.0.0`,s[`@fastify/middie`]=`^9.0.0`,s[`serve-static`]=`^2.2.0`):a===`h3`&&(s.h3=`^1.0.0`,s[`serve-static`]=`^2.2.0`);for(let e of r){let t=y[e];t&&!s[t]&&(s[t]=x(n,t))}return JSON.stringify({name:e,version:`0.0.0`,type:`module`,scripts:{dev:`kick dev`,"dev:debug":`kick dev:debug`,build:`kick build`,start:`kick start`,test:`vitest run`,"test:watch":`vitest`,typecheck:`tsc --noEmit`,typegen:`kick typegen`,lint:`eslint src/`,format:`prettier --write src/`},dependencies:s,devDependencies:{"@forinda/kickjs-cli":x(n,`@forinda/kickjs-cli`),"@forinda/kickjs-vite":x(n,`@forinda/kickjs-vite`),"@swc/core":`^1.15.21`,...a===`express`?{"@types/express":`^5.0.6`}:{},"@types/node":`^25.0.0`,"unplugin-swc":`^1.5.9`,vite:`^8.0.3`,vitest:`^4.1.2`,typescript:`^7.0.2`,prettier:`^3.8.1`}},null,2)}function C(){return`import { defineConfig } from 'vite'
|
|
12
12
|
import { resolve } from 'node:path'
|
|
13
13
|
import swc from 'unplugin-swc'
|
|
14
14
|
import { kickjsVitePlugin, envWatchPlugin } from '@forinda/kickjs-vite'
|
|
@@ -38,7 +38,7 @@ export default defineConfig({
|
|
|
38
38
|
},
|
|
39
39
|
},
|
|
40
40
|
})
|
|
41
|
-
`}function
|
|
41
|
+
`}function w(){return JSON.stringify({compilerOptions:{target:`ES2022`,module:`ESNext`,moduleResolution:`bundler`,lib:[`ES2022`],types:[`node`,`vite/client`],strict:!0,esModuleInterop:!0,skipLibCheck:!0,sourceMap:!0,declaration:!0,experimentalDecorators:!0,emitDecoratorMetadata:!0,outDir:`dist`,paths:{"@/*":[`./src/*`]}},include:[`src`,`.kickjs/types/**/*.d.ts`,`.kickjs/types/**/*.ts`]},null,2)}function T(){return JSON.stringify({semi:!1,singleQuote:!0,trailingComma:`all`,printWidth:100,tabWidth:2},null,2)}function ee(){return`# https://editorconfig.org
|
|
42
42
|
root = true
|
|
43
43
|
|
|
44
44
|
[*]
|
|
@@ -51,14 +51,14 @@ insert_final_newline = true
|
|
|
51
51
|
|
|
52
52
|
[*.md]
|
|
53
53
|
trim_trailing_whitespace = false
|
|
54
|
-
`}function
|
|
54
|
+
`}function te(){return`node_modules/
|
|
55
55
|
dist/
|
|
56
56
|
.env
|
|
57
57
|
coverage/
|
|
58
58
|
.DS_Store
|
|
59
59
|
*.tsbuildinfo
|
|
60
60
|
.kickjs/
|
|
61
|
-
`}function
|
|
61
|
+
`}function ne(){return`# Auto-detect text files and normalise line endings to LF
|
|
62
62
|
* text=auto eol=lf
|
|
63
63
|
|
|
64
64
|
# Explicitly mark generated / binary files
|
|
@@ -76,11 +76,11 @@ coverage/
|
|
|
76
76
|
pnpm-lock.yaml -diff linguist-generated
|
|
77
77
|
yarn.lock -diff linguist-generated
|
|
78
78
|
package-lock.json -diff linguist-generated
|
|
79
|
-
`}function
|
|
79
|
+
`}function re(){return`PORT=3000
|
|
80
80
|
NODE_ENV=development
|
|
81
|
-
`}function
|
|
81
|
+
`}function E(){return`PORT=3000
|
|
82
82
|
NODE_ENV=development
|
|
83
|
-
`}function
|
|
83
|
+
`}function D(){return`import { defineConfig } from 'vitest/config'
|
|
84
84
|
import swc from 'unplugin-swc'
|
|
85
85
|
|
|
86
86
|
export default defineConfig({
|
|
@@ -91,7 +91,7 @@ export default defineConfig({
|
|
|
91
91
|
include: ['src/**/*.test.ts'],
|
|
92
92
|
},
|
|
93
93
|
})
|
|
94
|
-
`}const
|
|
94
|
+
`}const O={express:{from:`@forinda/kickjs`,name:`expressRuntime`},fastify:{from:`@forinda/kickjs/fastify`,name:`fastifyRuntime`},h3:{from:`@forinda/kickjs/h3`,name:`h3Runtime`}};function k(e,t,n,r=[],i=`express`){let a=O[i],o=i===`express`;switch(t){case`minimal`:{let t=[],i=[],s=o?`import { bootstrap, ${a.name} } from '@forinda/kickjs'`:`import { bootstrap } from '@forinda/kickjs'\nimport { ${a.name} } from '${a.from}'`;r.includes(`swagger`)&&(t.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`),i.push(` SwaggerAdapter({ info: { title: '${e}', version: '${n}' } }),`)),r.includes(`devtools`)&&(t.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`),i.push(` DevToolsAdapter(),`));let c=t.length?t.join(`
|
|
95
95
|
`)+`
|
|
96
96
|
`:``,l=i.length?`,\n adapters: [\n${i.join(`
|
|
97
97
|
`)}\n ]`:``;return`import 'reflect-metadata'
|
|
@@ -131,14 +131,14 @@ export const app = await bootstrap({
|
|
|
131
131
|
requestLogger(),${d}
|
|
132
132
|
],
|
|
133
133
|
})
|
|
134
|
-
`}}}function
|
|
134
|
+
`}}}function A(){return`import { defineModules } from '@forinda/kickjs'
|
|
135
135
|
import { HelloModule } from './hello/hello.module'
|
|
136
136
|
|
|
137
137
|
// Remove HelloModule and run: kick g module <name>
|
|
138
138
|
// \`defineModules()\` returns a chainable list — \`kick g module\` appends
|
|
139
139
|
// \`.mount(NewModule())\` to the chain on every generation.
|
|
140
140
|
export const modules = defineModules().mount(HelloModule())
|
|
141
|
-
`}function
|
|
141
|
+
`}function j(e=`zod`){return e===`valibot`?`import { loadEnvFromSchema } from '@forinda/kickjs/config'
|
|
142
142
|
import { fromValibot } from '@forinda/kickjs-schema/valibot'
|
|
143
143
|
import * as v from 'valibot'
|
|
144
144
|
|
|
@@ -266,7 +266,7 @@ const envSchema = fromZod(
|
|
|
266
266
|
export const env = loadEnvFromSchema(envSchema)
|
|
267
267
|
|
|
268
268
|
export default envSchema
|
|
269
|
-
`}function
|
|
269
|
+
`}function M(){return`import { Service } from '@forinda/kickjs'
|
|
270
270
|
|
|
271
271
|
@Service()
|
|
272
272
|
export class HelloService {
|
|
@@ -278,7 +278,7 @@ export class HelloService {
|
|
|
278
278
|
return { status: 'ok', uptime: process.uptime() }
|
|
279
279
|
}
|
|
280
280
|
}
|
|
281
|
-
`}function
|
|
281
|
+
`}function N(){return`import { Controller, Get, Autowired, type Ctx } from '@forinda/kickjs'
|
|
282
282
|
import { HelloService } from './hello.service'
|
|
283
283
|
|
|
284
284
|
// \`Ctx<KickRoutes.HelloController['<method>']>\` is generated by
|
|
@@ -304,7 +304,7 @@ export class HelloController {
|
|
|
304
304
|
return this.helloService.healthCheck()
|
|
305
305
|
}
|
|
306
306
|
}
|
|
307
|
-
`}function
|
|
307
|
+
`}function P(){return`import { defineModule } from '@forinda/kickjs'
|
|
308
308
|
import { HelloController } from './hello.controller'
|
|
309
309
|
|
|
310
310
|
export const HelloModule = defineModule({
|
|
@@ -325,7 +325,7 @@ export const HelloModule = defineModule({
|
|
|
325
325
|
},
|
|
326
326
|
}),
|
|
327
327
|
})
|
|
328
|
-
`}function
|
|
328
|
+
`}function F(e,t=`inmemory`,n=`pnpm`,r=`express`){return`import { defineConfig } from '@forinda/kickjs-cli'
|
|
329
329
|
|
|
330
330
|
export default defineConfig({
|
|
331
331
|
pattern: '${e}',
|
|
@@ -377,13 +377,13 @@ export default defineConfig({
|
|
|
377
377
|
},
|
|
378
378
|
],
|
|
379
379
|
})
|
|
380
|
-
`}const
|
|
380
|
+
`}const I={kickjs:{pkg:`@forinda/kickjs`,peers:[`express`],description:`Unified framework: DI, decorators, routing, middleware`,core:!0},vite:{pkg:`@forinda/kickjs-vite`,peers:[`vite`],description:`Vite plugin: dev server, HMR, module discovery`,dev:!0,core:!0},cli:{pkg:`@forinda/kickjs-cli`,peers:[],description:`CLI tool and code generators`,dev:!0,core:!0},zod:{pkg:`zod`,peers:[],description:`Zod schema validation (env, DTOs, OpenAPI) — wrap with fromZod()`},valibot:{pkg:`valibot`,peers:[],description:`Valibot schema validation — wrap with fromValibot()`},yup:{pkg:`yup`,peers:[],description:`Yup schema validation — wrap with fromYup()`},auth:{pkg:`@forinda/kickjs-auth`,peers:[`jsonwebtoken`],description:`JWT, API key, OAuth strategies, @Public, @Roles (+ optional argon2/bcryptjs)`,deprecated:`auth is moving to BYO — compose @LoadAuthUser/@RequireRole/@Public from defineContextDecorator (see the BYO Auth recipe in the docs)`},ai:{pkg:`@forinda/kickjs-ai`,peers:[`zod`],description:`AI toolkit — LLM providers, tool definitions from controllers`},swagger:{pkg:`@forinda/kickjs-swagger`,peers:[],description:`OpenAPI spec + Swagger UI + ReDoc`},db:{pkg:`@forinda/kickjs-db`,peers:[],description:`kick/db core — schema DSL, migrations, KickDbClient, customType`},pg:{pkg:`@forinda/kickjs-db`,peers:[`pg`],description:`kick/db + PostgreSQL driver (use @forinda/kickjs-db/pg)`},sqlite:{pkg:`@forinda/kickjs-db`,peers:[`better-sqlite3`],description:`kick/db + SQLite driver (use @forinda/kickjs-db/sqlite)`},mysql:{pkg:`@forinda/kickjs-db`,peers:[`mysql2`],description:`kick/db + MySQL driver (use @forinda/kickjs-db/mysql)`},drizzle:{pkg:`@forinda/kickjs-drizzle`,peers:[`drizzle-orm`],description:`Drizzle ORM adapter + query builder`,deprecated:"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)"},prisma:{pkg:`@forinda/kickjs-prisma`,peers:[`@prisma/client`],description:`Prisma adapter + query builder`,deprecated:"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)"},ws:{pkg:`@forinda/kickjs-ws`,peers:[`ws`],description:`WebSocket with @WsController decorators`},devtools:{pkg:`@forinda/kickjs-devtools`,peers:[],description:`Development dashboard — routes, DI, metrics, health`,dev:!0},queue:{pkg:`@forinda/kickjs-queue`,peers:[],description:`Queue adapter (BullMQ/RabbitMQ/Kafka)`},"queue:bullmq":{pkg:`@forinda/kickjs-queue`,peers:[`bullmq`,`ioredis`],description:`Queue with BullMQ + Redis`},"queue:rabbitmq":{pkg:`@forinda/kickjs-queue`,peers:[`amqplib`],description:`Queue with RabbitMQ`},"queue:kafka":{pkg:`@forinda/kickjs-queue`,peers:[`kafkajs`],description:`Queue with Kafka`},"queue:redis-pubsub":{pkg:`@forinda/kickjs-queue`,peers:[`ioredis`],description:`Lightweight pub/sub via Redis (no persistence)`},mcp:{pkg:`@forinda/kickjs-mcp`,peers:[`@modelcontextprotocol/sdk`],description:`Model Context Protocol server — expose @Controller endpoints as AI tools`},testing:{pkg:`@forinda/kickjs-testing`,peers:[],description:`Test utilities and TestModule builder`,dev:!0}},L=Object.entries(I).filter(([e,t])=>!t.core&&!t.deprecated&&!e.includes(`:`)&&![`pg`,`sqlite`,`mysql`,`zod`,`valibot`,`yup`].includes(e)).map(([e])=>e).join(`, `),R={express:{prod:`multer`,dev:`@types/multer`,note:`Express uploads use multer (memory/disk storage, ctx.file / ctx.files).`},fastify:{prod:`@fastify/multipart`,note:`Fastify uploads use @fastify/multipart (buffered into ctx.file / ctx.files).`},h3:{note:`h3 parses multipart natively (readMultipartFormData) — no driver to install.`}};async function z(t=process.cwd()){let n=(await e(t))?.runtime;return n===`express`||n===`fastify`||n===`h3`?n:B(t)}function B(e=process.cwd()){let t=V(`package.json`,e);if(t)try{let e=JSON.parse(a(c(t,`package.json`),`utf-8`)),n={...e.dependencies,...e.devDependencies};if(`fastify`in n)return`fastify`;if(`h3`in n)return`h3`}catch{}return`express`}function V(e,t=process.cwd()){let n=t;for(;;){if(i(c(n,e)))return n;let t=o(n);if(t===n)return null;n=t}}function ie(){return V(`pnpm-lock.yaml`)?`pnpm`:V(`yarn.lock`)?`yarn`:V(`bun.lockb`)||V(`bun.lock`)?`bun`:V(`package-lock.json`)?`npm`:null}function H(){let e=process.cwd();for(;e;){let n=c(e,`package.json`);if(i(n))try{let e=JSON.parse(a(n,`utf-8`)).packageManager;if(typeof e==`string`){let n=e.split(`@`)[0];if(t.includes(n))return n}}catch{}let r=o(e);if(r===e)return null;e=r}return null}async function U(n){if(n&&t.includes(n))return{pm:n,source:`flag`};let r=await e(process.cwd());if(r?.packageManager&&t.includes(r.packageManager))return{pm:r.packageManager,source:`config`};let i=H();if(i)return{pm:i,source:`package.json`};let a=ie();return a?{pm:a,source:`lockfile`}:{pm:`npm`,source:`default`}}async function W(e){let{pm:t}=await U(e);return t}function G(e=!1){let t=Object.entries(I),n=Math.max(...t.map(([e])=>e.length)),r=t.filter(([,e])=>e.core),i=t.filter(([,e])=>!e.core),a=([e,t])=>{let r=e.padEnd(n+2),i=t.peers.length?` (+ ${t.peers.join(`, `)})`:``,a=t.deprecated?` [DEPRECATED — ${t.deprecated}]`:``;return` ${r} ${t.description}${i}${a}`};console.log(`
|
|
381
381
|
Core packages (always installed by \`kick new\`):
|
|
382
382
|
`);for(let e of r)console.log(a(e));if(e){console.log(`
|
|
383
383
|
Optional packages (add as needed):
|
|
384
384
|
`);for(let e of i)console.log(a(e))}else console.log(`\n Plus ${i.length} optional packages (auth, swagger, db, queue, …).`),console.log(" Run `kick add --list --all` for the full catalog.");console.log(`
|
|
385
|
-
Usage: kick add ai db swagger`),console.log(` kick add queue:bullmq`),console.log(` kick add upload # installs the multipart driver for your runtime`),console.log()}function
|
|
385
|
+
Usage: kick add ai db swagger`),console.log(` kick add queue:bullmq`),console.log(` kick add upload # installs the multipart driver for your runtime`),console.log()}function K(e,t,n=`express`){let r=new Set,i=new Set,a=[],o=[],s=[];for(let c of e){if(c===`upload`){let e=R[n];s.push(`upload (${n}): ${e.note}`),e.prod&&(t?i:r).add(e.prod),e.dev&&i.add(e.dev);continue}let e=I[c];if(!e){a.push(c);continue}e.deprecated&&o.push(`'${c}' (${e.pkg}) is deprecated — ${e.deprecated}`);let l=t||e.dev?i:r;l.add(e.pkg);for(let t of e.peers)l.add(t)}return{prodDeps:[...r],devDeps:[...i],unknown:a,warnings:o,notices:s}}function q(e){e.command(`list`).alias(`ls`).description(`List KickJS packages (core only; pair with --all for the full catalog)`).option(`--all`,`Include the full optional catalog`).action(e=>{G(!!e.all)})}function J(e){e.command(`add [packages...]`).description(`Add KickJS packages with their required dependencies`).option(`--pm <manager>`,`Package manager override`).option(`-D, --dev`,`Install as dev dependency`).option(`--list`,`List packages (core only by default; pair with --all)`).option(`--all`,`When listing, include the full optional catalog`).action(async(e,t)=>{if(t.list||e.length===0){G(!!t.all);return}let{pm:n,source:r}=await U(t.pm);console.log(`\n Using ${n} (resolved from ${r})`);let i=await z(process.cwd()),{prodDeps:a,devDeps:o,unknown:s,warnings:c,notices:l}=K(e,!!t.dev,i);for(let e of c)console.warn(`\n WARNING: ${e}`);for(let e of l)console.log(`\n ${e}`);if(!(s.length>0&&(console.log(`\n Unknown packages: ${s.join(`, `)}`),console.log(` Run "kick add --list" to see available packages.
|
|
386
386
|
`),a.length===0&&o.length===0))){if(a.length>0){let e=a,t=`${n} add ${e.join(` `)}`;console.log(`\n Installing ${e.length} dependency(ies):`);for(let t of e)console.log(` + ${t}`);console.log();try{d(t,{stdio:`inherit`})}catch{console.log(`\n Installation failed. Run manually:\n ${t}\n`)}}if(o.length>0){let e=o,t=`${n} add -D ${e.join(` `)}`;console.log(`\n Installing ${e.length} dev dependency(ies):`);for(let t of e)console.log(` + ${t} (dev)`);console.log();try{d(t,{stdio:`inherit`})}catch{console.log(`\n Installation failed. Run manually:\n ${t}\n`)}}console.log(` Done!
|
|
387
|
-
`)}})}const
|
|
388
|
-
Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${a} install failed. Run it manually.`)}}try{let{runTypegen:e}=await import(`./typegen-
|
|
389
|
-
Project scaffolded successfully!`),console.log();let
|
|
387
|
+
`)}})}const Y=o(l(import.meta.url)),X=JSON.parse(a(s(Y,`..`,`package.json`),`utf-8`)),ae=`^${X.version}`,oe=[`@forinda/kickjs`,`@forinda/kickjs-cli`,`@forinda/kickjs-schema`,`@forinda/kickjs-vite`,`@forinda/kickjs-swagger`,`@forinda/kickjs-ws`,`@forinda/kickjs-queue`,`@forinda/kickjs-devtools`,`@forinda/kickjs-testing`,`@forinda/kickjs-client`];async function Z(){let e=await Promise.all(oe.map(async e=>{let t=h(`npm`,[`view`,e,`version`]);return t&&/^\d+\.\d+\.\d+/.test(t)?[e,`^${t}`]:[e,ae]}));return Object.fromEntries(e)}function se(e,t){let n=h(`npm`,[`view`,`${e}@${t}`,`version`]);return n&&/^\d+\.\d+\.\d+/.test(n)?n:null}function Q(e){return(e??``).replace(/^[\^~>=<\s]+/,``)}function ce(e,t){let n=e=>Q(e).split(`-`)[0].split(`.`).map(e=>Number.parseInt(e,10)||0),[r=0,i=0,a=0]=n(e),[o=0,s=0,c=0]=n(t);return r===o?i===s?a>=c:i>s:r>o}function le(e,t,n){let r=h(`npm`,[`view`,`${e}@${t}`,`exports`,`--json`]);if(!r)return!1;try{let e=JSON.parse(r);return Object.prototype.hasOwnProperty.call(e,n)}catch{return!1}}async function $(e){let{name:t,directory:i,packageManager:a=`pnpm`,template:o=`rest`,defaultRepo:c=`inmemory`,packages:l=[],schemaLib:u=`zod`,runtime:f=`express`}=e,p=i,m=e=>console.log(` ${e}`);console.log(`\n Creating KickJS project: ${t}\n`),m(`Resolving package versions...`);let h=await Z();if(f!==`express`)if(le(`@forinda/kickjs`,`latest`,`./${f}`))m(`Using @forinda/kickjs@latest (stable ships the ${f} runtime)`);else{let e=[`@forinda/kickjs`,`@forinda/kickjs-cli`,`@forinda/kickjs-vite`],t=[],n=!1;for(let r of e){let e=se(r,`alpha`);e&&ce(e,Q(h[r]))&&(h[r]=`^${e}`,t.push(`${r}@^${e}`),r===`@forinda/kickjs`&&(n=!0))}m(n?`Using the alpha channel for the ${f} runtime: ${t.join(`, `)}`:`WARNING: could not resolve @forinda/kickjs@alpha — the ${f} runtime subpath may be missing. After install, run: ${a} add @forinda/kickjs@alpha`)}await n(s(p,`package.json`),S(t,o,h,l,u,f)),await n(s(p,`vite.config.ts`),C()),await n(s(p,`tsconfig.json`),w()),await n(s(p,`.prettierrc`),T()),await n(s(p,`.editorconfig`),ee()),await n(s(p,`.gitignore`),te()),await n(s(p,`.gitattributes`),ne()),await n(s(p,`.env`),re()),await n(s(p,`.env.example`),E()),await n(s(p,`src/config/index.ts`),j(u)),await n(s(p,`src/index.ts`),k(t,o,X.version,l,f)),await n(s(p,`src/modules/index.ts`),A()),await n(s(p,`src/modules/hello/hello.service.ts`),M()),await n(s(p,`src/modules/hello/hello.controller.ts`),N()),await n(s(p,`src/modules/hello/hello.module.ts`),P()),await n(s(p,`kick.config.ts`),F(o,c,a,f)),await n(s(p,`vitest.config.ts`),D()),await n(s(p,`README.md`),r(t,o,a));let{generateAgentDocs:g}=await import(`./agent-docs-B249TRF6.mjs`).then(e=>e.t);if(await g({outDir:p,name:t,pm:a,template:o,only:`all`,force:!0}),e.installDeps){console.log(`\n Installing dependencies with ${a}...\n`);try{d(`${a} install`,{cwd:p,stdio:`inherit`}),console.log(`
|
|
388
|
+
Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${a} install failed. Run it manually.`)}}try{let{runTypegen:e}=await import(`./typegen-CbMLPc5z.mjs`).then(e=>e.n);await e({cwd:p,allowDuplicates:!0,silent:!0})}catch{}if(e.initGit)try{d(`git init`,{cwd:p,stdio:`pipe`}),d(`git branch -M main`,{cwd:p,stdio:`pipe`}),d(`git add -A`,{cwd:p,stdio:`pipe`}),d(`git commit -m "chore: initial commit from kick new"`,{cwd:p,stdio:`pipe`}),m(`Git repository initialized`)}catch{m(`Warning: git init failed (git may not be installed)`)}console.log(`
|
|
389
|
+
Project scaffolded successfully!`),console.log();let _=p!==process.cwd();m(`Next steps:`),_&&m(` cd ${t}`),e.installDeps||m(` ${a} install`);let v={rest:`kick g module user`,ddd:`kick g module user --repo drizzle`,cqrs:`kick g module user --pattern cqrs`,minimal:`# add your routes to src/index.ts`};m(` ${v[o]??v.rest}`),m(` kick dev`),m(``),m(`Commands:`),m(` kick dev Start dev server with Vite HMR`),m(` kick build Production build via Vite`),m(` kick start Run production build`),m(``),m(`Generators:`),m(` kick g module <name> Full DDD module (controller, DTOs, use-cases, repo)`),m(` kick g scaffold <n> <f..> CRUD module from field definitions`),m(` kick g controller <name> Standalone controller`),m(` kick g service <name> @Service() class`),m(` kick g middleware <name> Express middleware`),m(` kick g guard <name> Route guard (auth, roles, etc.)`),m(` kick g adapter <name> AppAdapter with lifecycle hooks`),m(` kick g dto <name> Zod DTO schema`),m(` kick g config Generate kick.config.ts`),m(``),m(`Add packages:`),m(` kick add <pkg> Install a KickJS package + peers`),m(` kick add --list Show all available packages`),m(``),m(`Available: ${L}`),m(``)}export{J as a,W as c,_ as d,R as i,g as l,Z as n,q as o,I as r,z as s,$ as t,v as u};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v6.9.
|
|
2
|
+
* @forinda/kickjs-cli v6.9.2
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -926,4 +926,4 @@ Codex / Cursor / Gemini / Claude Code without copy-pasting.
|
|
|
926
926
|
CLI template. Hand-edited content is overwritten — keep customisation
|
|
927
927
|
in \`.agents/COPILOT.local.md\`.
|
|
928
928
|
`}export{S as a,u as c,C as i,f as l,b as n,y as o,w as r,v as s,x as t};
|
|
929
|
-
//# sourceMappingURL=project-docs-
|
|
929
|
+
//# sourceMappingURL=project-docs-nlJ0u0U1.mjs.map
|