@forinda/kickjs-cli 5.4.0 → 5.4.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.
Files changed (27) hide show
  1. package/dist/{builtins-K-nRJcJG.mjs → builtins-CB0cpCRy.mjs} +207 -190
  2. package/dist/{builtins-DBzZkJey.mjs → builtins-DNnIUbGs.mjs} +101 -99
  3. package/dist/builtins-DNnIUbGs.mjs.map +1 -0
  4. package/dist/cli.mjs +2 -2
  5. package/dist/{config-CCNnXhar.mjs → config-CAjDTnMg.mjs} +2 -2
  6. package/dist/{config-CQZ6Hppr.mjs → config-f_GHcOYT.mjs} +3 -3
  7. package/dist/{config-CQZ6Hppr.mjs.map → config-f_GHcOYT.mjs.map} +1 -1
  8. package/dist/{generator-extension-Bn2aH7kY.mjs → generator-extension-Ds2fzYZS.mjs} +99 -84
  9. package/dist/generator-extension-Ds2fzYZS.mjs.map +1 -0
  10. package/dist/index.d.mts.map +1 -1
  11. package/dist/index.mjs +2 -2
  12. package/dist/{plugin-DasN_2Zr.mjs → plugin-CiWyeMpX.mjs} +3 -3
  13. package/dist/{plugin-DasN_2Zr.mjs.map → plugin-CiWyeMpX.mjs.map} +1 -1
  14. package/dist/{plugin-D0C4ISZA.mjs → plugin-Dz0Yu4Ow.mjs} +2 -2
  15. package/dist/{rolldown-runtime-BTpMa50s.mjs → rolldown-runtime-iJll81ez.mjs} +1 -1
  16. package/dist/{run-plugins-Dk7KBKON.mjs → run-plugins-DBOc1G96.mjs} +2 -2
  17. package/dist/typegen-COBqEd4w.mjs +116 -0
  18. package/dist/typegen-DzmDwZvN.mjs +117 -0
  19. package/dist/typegen-DzmDwZvN.mjs.map +1 -0
  20. package/dist/{types-kAfWJgh0.mjs → types-DucsCMzP.mjs} +2 -2
  21. package/dist/{types-kAfWJgh0.mjs.map → types-DucsCMzP.mjs.map} +1 -1
  22. package/package.json +1 -1
  23. package/dist/builtins-DBzZkJey.mjs.map +0 -1
  24. package/dist/generator-extension-Bn2aH7kY.mjs.map +0 -1
  25. package/dist/typegen-Bl9kUVNL.mjs +0 -115
  26. package/dist/typegen-Bl9kUVNL.mjs.map +0 -1
  27. package/dist/typegen-DDQJNnUl.mjs +0 -114
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs-cli v5.4.0
2
+ * @forinda/kickjs-cli v5.4.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{t as e}from"./rolldown-runtime-BTpMa50s.mjs";import{a as t,i as n,r,t as i}from"./config-CCNnXhar.mjs";import{n as a,r as o}from"./plugin-D0C4ISZA.mjs";import{a as s,i as c,o as l,r as u,s as d,t as f}from"./typegen-DDQJNnUl.mjs";import{createRequire as p}from"node:module";import{cpSync as m,existsSync as h,mkdirSync as g,readFileSync as _,readdirSync as ee,rmSync as v,statSync as te,writeFileSync as ne}from"node:fs";import y,{basename as re,dirname as b,extname as ie,isAbsolute as ae,join as x,relative as S,resolve as C,sep as oe}from"node:path";import{fileURLToPath as se,pathToFileURL as w}from"node:url";import{execSync as T,fork as ce,spawn as le,spawnSync as ue}from"node:child_process";import{access as de,copyFile as fe,mkdir as pe,readFile as E,readdir as me,rm as he,stat as ge,writeFile as D}from"node:fs/promises";import*as O from"@clack/prompts";import k from"picocolors";import _e from"pluralize";import{glob as ve}from"glob";import{groupAssetKeys as ye}from"@forinda/kickjs";import{arch as be,platform as xe,release as Se}from"node:os";import{generate as Ce,migrateDown as we,migrateLatest as Te,migrateRollback as Ee,migrateStatus as De,migrateUp as Oe,renderSchemaSource as ke,resolveDbConfig as Ae}from"@forinda/kickjs-db";function je(e,t,n){T(e,{cwd:t,stdio:`inherit`,env:n?{...process.env,...n}:process.env})}function Me(e,t,n){let r=ue(process.execPath,[e],{cwd:n,stdio:`inherit`,env:{...process.env,...t}});r.status!==0&&process.exit(r.status??1)}let Ne=!1;function A(e){Ne=e}const Pe=new Set([`.ts`,`.tsx`,`.js`,`.jsx`,`.mjs`,`.cjs`,`.json`,`.md`]);async function j(e,t){Ne||(await pe(b(e),{recursive:!0}),await D(e,t,`utf-8`),Pe.has(ie(e))&&await Ie(e,t).catch(()=>{}))}let M;async function Fe(e){if(M!==void 0)return M;try{M=await import(p(x(e,`package.json`)).resolve(`oxfmt`))}catch{M=null}return M}async function Ie(e,t){let n=await Fe(process.cwd());if(!n)return;let r=await Le(e);if(r===null)return;let i=await n.format(e,t,r);i.code!==t&&await D(e,i.code,`utf-8`)}const N=new Map;async function Le(e){let t=b(e),n=t;if(N.has(n))return N.get(n);for(;;){let e=x(t,`.oxfmtrc.json`);if(h(e))try{let t=await E(e,`utf-8`),r=JSON.parse(t);return delete r.$schema,delete r.ignorePatterns,N.set(n,r),r}catch{return N.set(n,null),null}let r=b(t);if(r===t)return N.set(n,null),null;t=r}}async function Re(e){try{return await de(e),!0}catch{return!1}}const ze={auth:`@forinda/kickjs-auth`,swagger:`@forinda/kickjs-swagger`,ws:`@forinda/kickjs-ws`,queue:`@forinda/kickjs-queue`,devtools:`@forinda/kickjs-devtools`};function Be(e,t,n,r=[]){let i={"@forinda/kickjs":n,dotenv:`^17.3.1`,express:`^5.1.0`,"reflect-metadata":`^0.2.2`,zod:`^4.3.6`,pino:`^10.3.1`,"pino-pretty":`^13.1.3`};for(let e of r){let t=ze[e];t&&!i[t]&&(i[t]=n)}return JSON.stringify({name:e,version:n.replace(`^`,``),type:`module`,scripts:{dev:`vite`,"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:i,devDependencies:{"@forinda/kickjs-cli":n,"@forinda/kickjs-vite":n,"@swc/core":`^1.15.21`,"@types/express":`^5.0.6`,"@types/node":`^25.0.0`,"unplugin-swc":`^1.5.9`,vite:`^8.0.3`,vitest:`^4.1.2`,typescript:`^6.0.3`,prettier:`^3.8.1`}},null,2)}function Ve(){return`import { defineConfig } from 'vite'
11
+ import{t as e}from"./rolldown-runtime-iJll81ez.mjs";import{a as t,i as n,r,t as i}from"./config-CAjDTnMg.mjs";import{n as a,r as o}from"./plugin-Dz0Yu4Ow.mjs";import{a as s,c,i as l,n as u,o as d,s as f,t as p}from"./typegen-COBqEd4w.mjs";import{createRequire as m}from"node:module";import{cpSync as h,existsSync as g,mkdirSync as _,readFileSync as v,readdirSync as y,rmSync as ee,statSync as te,writeFileSync as ne}from"node:fs";import b,{basename as re,dirname as x,extname as ie,isAbsolute as ae,join as S,relative as C,resolve as w,sep as oe}from"node:path";import{fileURLToPath as se,pathToFileURL as T}from"node:url";import{execFileSync as ce,execSync as E,fork as le,spawn as ue,spawnSync as de}from"node:child_process";import{access as fe,copyFile as pe,mkdir as me,readFile as D,readdir as he,rm as ge,stat as _e,writeFile as O}from"node:fs/promises";import*as k from"@clack/prompts";import A from"picocolors";import ve from"pluralize";import{glob as ye}from"glob";import{groupAssetKeys as be}from"@forinda/kickjs";import{arch as xe,platform as Se,release as Ce}from"node:os";import{generate as we,migrateDown as Te,migrateLatest as Ee,migrateRollback as De,migrateStatus as Oe,migrateUp as ke,renderSchemaSource as Ae,resolveDbConfig as je}from"@forinda/kickjs-db";function Me(e,t,n){E(e,{cwd:t,stdio:`inherit`,env:n?{...process.env,...n}:process.env})}function Ne(e,t,n){let r=de(process.execPath,[e],{cwd:n,stdio:`inherit`,env:{...process.env,...t}});r.status!==0&&process.exit(r.status??1)}let Pe=!1;function j(e){Pe=e}const Fe=new Set([`.ts`,`.tsx`,`.js`,`.jsx`,`.mjs`,`.cjs`,`.json`,`.md`]);async function M(e,t){Pe||(await me(x(e),{recursive:!0}),await O(e,t,`utf-8`),Fe.has(ie(e))&&await Le(e,t).catch(()=>{}))}let N;async function Ie(e){if(N!==void 0)return N;try{N=await import(m(S(e,`package.json`)).resolve(`oxfmt`))}catch{N=null}return N}async function Le(e,t){let n=await Ie(process.cwd());if(!n)return;let r=await Re(e);if(r===null)return;let i=await n.format(e,t,r);i.code!==t&&await O(e,i.code,`utf-8`)}const P=new Map;async function Re(e){let t=x(e),n=t;if(P.has(n))return P.get(n);for(;;){let e=S(t,`.oxfmtrc.json`);if(g(e))try{let t=await D(e,`utf-8`),r=JSON.parse(t);return delete r.$schema,delete r.ignorePatterns,P.set(n,r),r}catch{return P.set(n,null),null}let r=x(t);if(r===t)return P.set(n,null),null;t=r}}async function ze(e){try{return await fe(e),!0}catch{return!1}}const Be={auth:`@forinda/kickjs-auth`,swagger:`@forinda/kickjs-swagger`,ws:`@forinda/kickjs-ws`,queue:`@forinda/kickjs-queue`,devtools:`@forinda/kickjs-devtools`};function Ve(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 He(e,t,n,r=[]){let i={"@forinda/kickjs":Ve(n,`@forinda/kickjs`),dotenv:`^17.3.1`,express:`^5.1.0`,"reflect-metadata":`^0.2.2`,zod:`^4.3.6`,pino:`^10.3.1`,"pino-pretty":`^13.1.3`};for(let e of r){let t=Be[e];t&&!i[t]&&(i[t]=Ve(n,t))}return JSON.stringify({name:e,version:`0.0.0`,type:`module`,scripts:{dev:`vite`,"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:i,devDependencies:{"@forinda/kickjs-cli":Ve(n,`@forinda/kickjs-cli`),"@forinda/kickjs-vite":Ve(n,`@forinda/kickjs-vite`),"@swc/core":`^1.15.21`,"@types/express":`^5.0.6`,"@types/node":`^25.0.0`,"unplugin-swc":`^1.5.9`,vite:`^8.0.3`,vitest:`^4.1.2`,typescript:`^6.0.3`,prettier:`^3.8.1`}},null,2)}function Ue(){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'
@@ -43,7 +43,7 @@ export default defineConfig({
43
43
  },
44
44
  },
45
45
  })
46
- `}function He(){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 Ue(){return JSON.stringify({semi:!1,singleQuote:!0,trailingComma:`all`,printWidth:100,tabWidth:2},null,2)}function We(){return`# https://editorconfig.org
46
+ `}function We(){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 Ge(){return JSON.stringify({semi:!1,singleQuote:!0,trailingComma:`all`,printWidth:100,tabWidth:2},null,2)}function Ke(){return`# https://editorconfig.org
47
47
  root = true
48
48
 
49
49
  [*]
@@ -56,14 +56,14 @@ insert_final_newline = true
56
56
 
57
57
  [*.md]
58
58
  trim_trailing_whitespace = false
59
- `}function Ge(){return`node_modules/
59
+ `}function qe(){return`node_modules/
60
60
  dist/
61
61
  .env
62
62
  coverage/
63
63
  .DS_Store
64
64
  *.tsbuildinfo
65
65
  .kickjs/
66
- `}function Ke(){return`# Auto-detect text files and normalise line endings to LF
66
+ `}function Je(){return`# Auto-detect text files and normalise line endings to LF
67
67
  * text=auto eol=lf
68
68
 
69
69
  # Explicitly mark generated / binary files
@@ -81,11 +81,11 @@ coverage/
81
81
  pnpm-lock.yaml -diff linguist-generated
82
82
  yarn.lock -diff linguist-generated
83
83
  package-lock.json -diff linguist-generated
84
- `}function qe(){return`PORT=3000
84
+ `}function Ye(){return`PORT=3000
85
85
  NODE_ENV=development
86
- `}function Je(){return`PORT=3000
86
+ `}function Xe(){return`PORT=3000
87
87
  NODE_ENV=development
88
- `}function Ye(){return`import { defineConfig } from 'vitest/config'
88
+ `}function Ze(){return`import { defineConfig } from 'vitest/config'
89
89
  import swc from 'unplugin-swc'
90
90
 
91
91
  export default defineConfig({
@@ -96,7 +96,7 @@ export default defineConfig({
96
96
  include: ['src/**/*.test.ts'],
97
97
  },
98
98
  })
99
- `}function Xe(e,t,n,r=[]){switch(t){case`cqrs`:{let t=[],i=[];return r.includes(`devtools`)&&(t.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`),i.push(` DevToolsAdapter(),`)),r.includes(`swagger`)&&(t.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`),i.push(` SwaggerAdapter({\n info: { title: '${e}', version: '${n}' },\n }),`)),`import 'reflect-metadata'
99
+ `}function Qe(e,t,n,r=[]){switch(t){case`cqrs`:{let t=[],i=[];return r.includes(`devtools`)&&(t.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`),i.push(` DevToolsAdapter(),`)),r.includes(`swagger`)&&(t.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`),i.push(` SwaggerAdapter({\n info: { title: '${e}', version: '${n}' },\n }),`)),`import 'reflect-metadata'
100
100
  // Side-effect import — registers the extended env schema with kickjs
101
101
  // **before** any controller / service / @Value gets resolved. Without
102
102
  // this line ConfigService.get('YOUR_KEY') returns undefined because the
@@ -166,14 +166,14 @@ export const app = await bootstrap({
166
166
  express.json(),
167
167
  ],
168
168
  })
169
- `}}}function Ze(){return`import type { AppModuleEntry } from '@forinda/kickjs'
169
+ `}}}function $e(){return`import { defineModules } from '@forinda/kickjs'
170
170
  import { HelloModule } from './hello/hello.module'
171
171
 
172
172
  // Remove HelloModule and run: kick g module <name>
173
- // Modules built with \`defineModule\` are called as factoriesthe
174
- // invocation produces the AppModule instance bootstrap registers.
175
- export const modules: AppModuleEntry[] = [HelloModule()]
176
- `}function Qe(){return`import { defineEnv, loadEnv } from '@forinda/kickjs/config'
173
+ // \`defineModules()\` returns a chainable list\`kick g module\` appends
174
+ // \`.mount(NewModule())\` to the chain on every generation.
175
+ export const modules = defineModules().mount(HelloModule())
176
+ `}function et(){return`import { defineEnv, loadEnv } from '@forinda/kickjs/config'
177
177
  import { z } from 'zod'
178
178
 
179
179
  /**
@@ -208,7 +208,7 @@ const envSchema = defineEnv((base) =>
208
208
  export const env = loadEnv(envSchema)
209
209
 
210
210
  export default envSchema
211
- `}function $e(){return`import { Service } from '@forinda/kickjs'
211
+ `}function tt(){return`import { Service } from '@forinda/kickjs'
212
212
 
213
213
  @Service()
214
214
  export class HelloService {
@@ -220,7 +220,7 @@ export class HelloService {
220
220
  return { status: 'ok', uptime: process.uptime() }
221
221
  }
222
222
  }
223
- `}function et(){return`import { Controller, Get, Autowired, type Ctx } from '@forinda/kickjs'
223
+ `}function nt(){return`import { Controller, Get, Autowired, type Ctx } from '@forinda/kickjs'
224
224
  import { HelloService } from './hello.service'
225
225
 
226
226
  // \`Ctx<KickRoutes.HelloController['<method>']>\` is generated by
@@ -242,7 +242,7 @@ export class HelloController {
242
242
  ctx.json(this.helloService.healthCheck())
243
243
  }
244
244
  }
245
- `}function tt(){return`import { defineModule } from '@forinda/kickjs'
245
+ `}function rt(){return`import { defineModule } from '@forinda/kickjs'
246
246
  import { HelloController } from './hello.controller'
247
247
 
248
248
  export const HelloModule = defineModule({
@@ -263,7 +263,7 @@ export const HelloModule = defineModule({
263
263
  },
264
264
  }),
265
265
  })
266
- `}function nt(e,t=`inmemory`,n=`pnpm`){return`import { defineConfig } from '@forinda/kickjs-cli'
266
+ `}function it(e,t=`inmemory`,n=`pnpm`){return`import { defineConfig } from '@forinda/kickjs-cli'
267
267
 
268
268
  export default defineConfig({
269
269
  pattern: '${e}',
@@ -307,7 +307,7 @@ export default defineConfig({
307
307
  },
308
308
  ],
309
309
  })
310
- `}function rt(e,t,n){let r={rest:`REST API`,ddd:`Domain-Driven Design`,cqrs:`CQRS + Event-Driven`,minimal:`Minimal`},i=[`@forinda/kickjs`,`@forinda/kickjs-vite`];return t!==`minimal`&&i.push(`@forinda/kickjs-swagger`,`@forinda/kickjs-devtools`),t===`cqrs`&&i.push(`@forinda/kickjs-queue`,`@forinda/kickjs-ws`),`# ${e}
310
+ `}function at(e,t,n){let r={rest:`REST API`,ddd:`Domain-Driven Design`,cqrs:`CQRS + Event-Driven`,minimal:`Minimal`},i=[`@forinda/kickjs`,`@forinda/kickjs-vite`];return t!==`minimal`&&i.push(`@forinda/kickjs-swagger`,`@forinda/kickjs-devtools`),t===`cqrs`&&i.push(`@forinda/kickjs-queue`,`@forinda/kickjs-ws`),`# ${e}
311
311
 
312
312
  A **${r[t]??`REST API`}** built with [KickJS](https://forinda.github.io/kick-js/) — a decorator-driven Node.js framework on Express 5 and TypeScript.
313
313
 
@@ -370,7 +370,7 @@ Copy \`.env.example\` to \`.env\` and configure:
370
370
 
371
371
  - [KickJS Documentation](https://forinda.github.io/kick-js/)
372
372
  - [CLI Reference](https://forinda.github.io/kick-js/api/cli.html)
373
- `}function it(e,t,n){return`# CLAUDE.md — ${e}
373
+ `}function ot(e,t,n){return`# CLAUDE.md — ${e}
374
374
 
375
375
  **Read \`./AGENTS.md\` first.** It is the canonical, multi-agent
376
376
  reference for this project (Claude, Copilot, Codex, Gemini, etc.) —
@@ -436,7 +436,7 @@ When generating or modifying code in this project, stay aligned with the v4 conv
436
436
  - **Refresh these files**: \`kick g agents -f\` regenerates \`AGENTS.md\` + \`CLAUDE.md\` from the latest CLI templates. Hand-edited content is overwritten — keep customisation in \`AGENTS.local.md\`.
437
437
 
438
438
  For everything else (controllers, services, modules, RequestContext API, generators, CLI commands, package additions, env wiring, troubleshooting) → \`AGENTS.md\`.
439
- `}function at(e,t,n){return`# AGENTS.md — AI Agent Guide for ${e}
439
+ `}function st(e,t,n){return`# AGENTS.md — AI Agent Guide for ${e}
440
440
 
441
441
  This guide is the **canonical, multi-agent reference** for this KickJS
442
442
  application — Claude, Copilot, Codex, Gemini, etc. all read it first.
@@ -540,8 +540,10 @@ mistakes:
540
540
  inline registration in the entry file:
541
541
 
542
542
  \`\`\`ts
543
- // src/modules/index.ts
544
- export const modules: AppModuleEntry[] = [HelloModule(), UsersModule(), ...]
543
+ // src/modules/index.ts — fluent chain (default for \`modules.style: 'define'\`)
544
+ export const modules = defineModules().mount(HelloModule()).mount(UsersModule())
545
+ // OR with \`modules.style: 'class'\`:
546
+ // export const modules: AppModuleEntry[] = [HelloModule, UsersModule]
545
547
 
546
548
  // src/middleware/index.ts
547
549
  export const middleware = [helmet(), cors(), requestId(), ...]
@@ -657,8 +659,8 @@ If not using generators:
657
659
  - [ ] Create \`src/modules/<name>/<name>.controller.ts\`
658
660
  - [ ] Add \`@Controller()\` decorator
659
661
  - [ ] Add route handlers with \`@Get()\`, \`@Post()\`, etc.
660
- - [ ] Create module file with \`defineModule({ name, build: () => ({ routes() { return { path, controller } } }) })\` (the framework derives the Express router from the controller)
661
- - [ ] Register module in \`src/modules/index.ts\` (\`AppModuleEntry[]\` array call the factory at the registration site: \`[MyModule()]\`)
662
+ - [ ] Create module file with \`defineModule({ name, build: () => ({ routes() { return { path, controller } } }) })\` the framework derives the Express router from the controller. Class-form (\`class XModule implements AppModule\`) is the legacy alternative; toggle via \`kick.config.ts > modules.style\`.
663
+ - [ ] Register module in \`src/modules/index.ts\`. Default form is the fluent chain: \`defineModules().mount(MyModule()).mount(...)\`. \`kick g module <name>\` appends \`.mount(NewModule())\` automatically.
662
664
  - [ ] Test with \`kick dev\`
663
665
 
664
666
  ### Manual Service
@@ -860,7 +862,9 @@ These work anywhere — scripts, plain files, outside \`@Service\`/\`@Controller
860
862
  ### Dependency Injection
861
863
  | Decorator | Purpose |
862
864
  |-----------|---------|
863
- | \`AppModule\` interface | Define feature module (implements \`routes()\`) |
865
+ | \`defineModule({...})\` | Define feature module (factory; preferred — paired with \`defineModules()\` registry) |
866
+ | \`defineModules()\` | Build the modules registry as a chainable list (\`.mount(X())\`) |
867
+ | \`AppModule\` interface | Legacy module shape — \`class X implements AppModule\` (toggle via \`modules.style: 'class'\`) |
864
868
  | \`@Service()\` | Register singleton service |
865
869
  | \`@Repository()\` | Register repository |
866
870
  | \`@Autowired()\` | Property injection |
@@ -877,7 +881,7 @@ is a value other code reads off \`ctx\`.
877
881
  |---------|----------------|
878
882
  | \`defineContextDecorator({ key, deps, dependsOn, optional, onError, resolve })\` | \`@forinda/kickjs\` |
879
883
  | Method/class decorator | \`@LoadX\` on a controller method/class |
880
- | Module hook | \`AppModule.contributors?(): ContributorRegistration[]\` |
884
+ | Module hook | \`build: () => ({ contributors() { return [...] } })\` (\`defineModule\`) — or \`AppModule.contributors?()\` for class form |
881
885
  | Adapter hook | \`AppAdapter.contributors?(): ContributorRegistration[]\` |
882
886
  | Global registration | \`bootstrap({ contributors: [LoadX.registration] })\` |
883
887
  | Type augmentation | \`declare module '@forinda/kickjs' { interface ContextMeta { ... } }\` |
@@ -939,7 +943,7 @@ ${t===`cqrs`?`### Background Jobs
939
943
  - [Decorators Guide](https://forinda.github.io/kick-js/guide/decorators.html)
940
944
  - [DI System](https://forinda.github.io/kick-js/guide/dependency-injection.html)
941
945
  - [Testing](https://forinda.github.io/kick-js/api/testing.html)
942
- `}function ot(e,t,n){return`# kickjs-skills.md — Task Skills for AI Agents (${e})
946
+ `}function ct(e,t,n){return`# kickjs-skills.md — Task Skills for AI Agents (${e})
943
947
 
944
948
  This file is the agent-facing **skills index** for KickJS work in this
945
949
  repo. Each block below is a short, rigid workflow keyed to a specific
@@ -1074,8 +1078,10 @@ description: Use when src/index.ts is accumulating module/middleware/plugin/adap
1074
1078
  **Refactor target**:
1075
1079
 
1076
1080
  \`\`\`ts
1077
- // src/modules/index.ts
1078
- export const modules: AppModuleClass[] = [HelloModule, UsersModule, ...]
1081
+ // src/modules/index.ts — fluent chain (default for \`modules.style: 'define'\`)
1082
+ export const modules = defineModules().mount(HelloModule()).mount(UsersModule())
1083
+ // OR for class-form projects (\`modules.style: 'class'\`):
1084
+ // export const modules: AppModuleEntry[] = [HelloModule, UsersModule]
1079
1085
 
1080
1086
  // src/middleware/index.ts
1081
1087
  export const middleware = [helmet(), cors(), requestId(), ...]
@@ -1186,16 +1192,16 @@ description: Patterns to refuse outright when the user asks for them — they br
1186
1192
  - [Decorators](https://forinda.github.io/kick-js/guide/decorators.html)
1187
1193
  - [Context Decorators](https://forinda.github.io/kick-js/guide/context-decorators.html)
1188
1194
  - [Testing](https://forinda.github.io/kick-js/api/testing.html)
1189
- `}const st=b(se(import.meta.url)),ct=JSON.parse(_(x(st,`..`,`package.json`),`utf-8`)),lt=`^${ct.version}`;async function ut(e){let{name:t,directory:n,packageManager:r=`pnpm`,template:i=`rest`,defaultRepo:a=`inmemory`,packages:o=[]}=e,s=n,c=e=>console.log(` ${e}`);if(console.log(`\n Creating KickJS project: ${t}\n`),await j(x(s,`package.json`),Be(t,i,lt,o)),await j(x(s,`vite.config.ts`),Ve()),await j(x(s,`tsconfig.json`),He()),await j(x(s,`.prettierrc`),Ue()),await j(x(s,`.editorconfig`),We()),await j(x(s,`.gitignore`),Ge()),await j(x(s,`.gitattributes`),Ke()),await j(x(s,`.env`),qe()),await j(x(s,`.env.example`),Je()),await j(x(s,`src/config/index.ts`),Qe()),await j(x(s,`src/index.ts`),Xe(t,i,ct.version,o)),await j(x(s,`src/modules/index.ts`),Ze()),await j(x(s,`src/modules/hello/hello.service.ts`),$e()),await j(x(s,`src/modules/hello/hello.controller.ts`),et()),await j(x(s,`src/modules/hello/hello.module.ts`),tt()),await j(x(s,`kick.config.ts`),nt(i,a,r)),await j(x(s,`vitest.config.ts`),Ye()),await j(x(s,`README.md`),rt(t,i,r)),await j(x(s,`CLAUDE.md`),it(t,i,r)),await j(x(s,`AGENTS.md`),at(t,i,r)),await j(x(s,`kickjs-skills.md`),ot(t,i,r)),e.installDeps){console.log(`\n Installing dependencies with ${r}...\n`);try{T(`${r} install`,{cwd:s,stdio:`inherit`}),console.log(`
1190
- Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${r} install failed. Run it manually.`)}}try{let{runTypegen:e}=await import(`./typegen-DDQJNnUl.mjs`).then(e=>e.n);await e({cwd:s,allowDuplicates:!0,silent:!0})}catch{}if(e.initGit)try{T(`git init`,{cwd:s,stdio:`pipe`}),T(`git branch -M main`,{cwd:s,stdio:`pipe`}),T(`git add -A`,{cwd:s,stdio:`pipe`}),T(`git commit -m "chore: initial commit from kick new"`,{cwd:s,stdio:`pipe`}),c(`Git repository initialized`)}catch{c(`Warning: git init failed (git may not be installed)`)}console.log(`
1191
- Project scaffolded successfully!`),console.log();let l=s!==process.cwd();c(`Next steps:`),l&&c(` cd ${t}`),e.installDeps||c(` ${r} install`);let u={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`};c(` ${u[i]??u.rest}`),c(` kick dev`),c(``),c(`Commands:`),c(` kick dev Start dev server with Vite HMR`),c(` kick build Production build via Vite`),c(` kick start Run production build`),c(``),c(`Generators:`),c(` kick g module <name> Full DDD module (controller, DTOs, use-cases, repo)`),c(` kick g scaffold <n> <f..> CRUD module from field definitions`),c(` kick g controller <name> Standalone controller`),c(` kick g service <name> @Service() class`),c(` kick g middleware <name> Express middleware`),c(` kick g guard <name> Route guard (auth, roles, etc.)`),c(` kick g adapter <name> AppAdapter with lifecycle hooks`),c(` kick g dto <name> Zod DTO schema`),i===`cqrs`&&c(` kick g job <name> Queue job processor`),c(` kick g config Generate kick.config.ts`),c(``),c(`Add packages:`),c(` kick add <pkg> Install a KickJS package + peers`),c(` kick add --list Show all available packages`),c(``),c(`Available: auth, swagger, drizzle, prisma, ws, queue, devtools, mcp, testing`),c(``)}const dt={GET:k.green,POST:k.cyan,PUT:k.yellow,PATCH:k.magenta,DELETE:k.red};function ft(e){return(dt[e]??k.dim)(e.padEnd(7))}function pt(e){let t=`[${e}]`.padEnd(10);switch(e){case`CRITICAL`:return k.red(t);case`WARNING`:return k.yellow(t);case`INFO`:return k.blue(k.dim(t));default:return t}}k.green(`✓`),k.red(`✖`),k.yellow(`⚠`),k.blue(`ℹ`);function mt(e){O.intro(k.bgCyan(k.black(` ${e} `)))}function P(e){O.outro(e)}function ht(e){O.isCancel(e)&&(O.cancel(`Operation cancelled.`),process.exit(0))}async function gt(e){let t=await O.text(e);return ht(t),t}async function _t(e){let t=await O.select(e);return ht(t),t}async function vt(e){let t=await O.multiselect(e);return ht(t),t}async function F(e){let t=await O.confirm(e);return ht(t),t}function yt(){return O.spinner()}const I=O.log,bt={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},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`},"db-pg":{pkg:`@forinda/kickjs-db-pg`,peers:[`pg`],description:`kick/db PostgreSQL dialect + adapter (pgDialect, pgAdapter)`},drizzle:{pkg:`@forinda/kickjs-drizzle`,peers:[`drizzle-orm`],description:`Drizzle ORM adapter + query builder`},prisma:{pkg:`@forinda/kickjs-prisma`,peers:[`@prisma/client`],description:`Prisma adapter + query builder`},ws:{pkg:`@forinda/kickjs-ws`,peers:[`socket.io`],description:`WebSocket with @WsController decorators`},devtools:{pkg:`@forinda/kickjs-devtools`,peers:[],description:`Development dashboard — routes, DI, metrics, health`,dev:!0},auth:{pkg:`@forinda/kickjs-auth`,peers:[`jsonwebtoken`],description:`Authentication — JWT, API key, and custom strategies`},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`},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}};function L(e,t=process.cwd()){let n=t;for(;;){if(h(C(n,e)))return n;let t=b(n);if(t===n)return null;n=t}}function xt(){return L(`pnpm-lock.yaml`)?`pnpm`:L(`yarn.lock`)?`yarn`:L(`bun.lockb`)||L(`bun.lock`)?`bun`:L(`package-lock.json`)?`npm`:null}function St(){let e=process.cwd();for(;e;){let t=C(e,`package.json`);if(h(t))try{let e=JSON.parse(_(t,`utf-8`)).packageManager;if(typeof e==`string`){let t=e.split(`@`)[0];if(i.includes(t))return t}}catch{}let n=b(e);if(n===e)return null;e=n}return null}async function Ct(e){if(e&&i.includes(e))return{pm:e,source:`flag`};let t=await r(process.cwd());if(t?.packageManager&&i.includes(t.packageManager))return{pm:t.packageManager,source:`config`};let n=St();if(n)return{pm:n,source:`package.json`};let a=xt();return a?{pm:a,source:`lockfile`}:{pm:`npm`,source:`default`}}async function wt(e){let{pm:t}=await Ct(e);return t}function Tt(e=!1){let t=Object.entries(bt),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(`, `)})`:``;return` ${r} ${t.description}${i}`};console.log(`
1195
+ `}const lt=x(se(import.meta.url)),ut=JSON.parse(v(S(lt,`..`,`package.json`),`utf-8`)),dt=`^${ut.version}`,ft=[`@forinda/kickjs`,`@forinda/kickjs-cli`,`@forinda/kickjs-vite`,`@forinda/kickjs-auth`,`@forinda/kickjs-swagger`,`@forinda/kickjs-ws`,`@forinda/kickjs-queue`,`@forinda/kickjs-devtools`,`@forinda/kickjs-testing`];async function pt(){let e=await Promise.all(ft.map(async e=>{try{let t=ce(`npm`,[`view`,e,`version`],{encoding:`utf-8`,timeout:5e3,stdio:[`ignore`,`pipe`,`ignore`]}).toString().trim();if(t&&/^\d+\.\d+\.\d+/.test(t))return[e,`^${t}`]}catch{}return[e,dt]}));return Object.fromEntries(e)}async function mt(e){let{name:t,directory:n,packageManager:r=`pnpm`,template:i=`rest`,defaultRepo:a=`inmemory`,packages:o=[]}=e,s=n,c=e=>console.log(` ${e}`);console.log(`\n Creating KickJS project: ${t}\n`),c(`Resolving package versions...`);let l=await pt();if(await M(S(s,`package.json`),He(t,i,l,o)),await M(S(s,`vite.config.ts`),Ue()),await M(S(s,`tsconfig.json`),We()),await M(S(s,`.prettierrc`),Ge()),await M(S(s,`.editorconfig`),Ke()),await M(S(s,`.gitignore`),qe()),await M(S(s,`.gitattributes`),Je()),await M(S(s,`.env`),Ye()),await M(S(s,`.env.example`),Xe()),await M(S(s,`src/config/index.ts`),et()),await M(S(s,`src/index.ts`),Qe(t,i,ut.version,o)),await M(S(s,`src/modules/index.ts`),$e()),await M(S(s,`src/modules/hello/hello.service.ts`),tt()),await M(S(s,`src/modules/hello/hello.controller.ts`),nt()),await M(S(s,`src/modules/hello/hello.module.ts`),rt()),await M(S(s,`kick.config.ts`),it(i,a,r)),await M(S(s,`vitest.config.ts`),Ze()),await M(S(s,`README.md`),at(t,i,r)),await M(S(s,`CLAUDE.md`),ot(t,i,r)),await M(S(s,`AGENTS.md`),st(t,i,r)),await M(S(s,`kickjs-skills.md`),ct(t,i,r)),e.installDeps){console.log(`\n Installing dependencies with ${r}...\n`);try{E(`${r} install`,{cwd:s,stdio:`inherit`}),console.log(`
1196
+ Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${r} install failed. Run it manually.`)}}try{let{runTypegen:e}=await import(`./typegen-COBqEd4w.mjs`).then(e=>e.r);await e({cwd:s,allowDuplicates:!0,silent:!0})}catch{}if(e.initGit)try{E(`git init`,{cwd:s,stdio:`pipe`}),E(`git branch -M main`,{cwd:s,stdio:`pipe`}),E(`git add -A`,{cwd:s,stdio:`pipe`}),E(`git commit -m "chore: initial commit from kick new"`,{cwd:s,stdio:`pipe`}),c(`Git repository initialized`)}catch{c(`Warning: git init failed (git may not be installed)`)}console.log(`
1197
+ Project scaffolded successfully!`),console.log();let u=s!==process.cwd();c(`Next steps:`),u&&c(` cd ${t}`),e.installDeps||c(` ${r} install`);let d={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`};c(` ${d[i]??d.rest}`),c(` kick dev`),c(``),c(`Commands:`),c(` kick dev Start dev server with Vite HMR`),c(` kick build Production build via Vite`),c(` kick start Run production build`),c(``),c(`Generators:`),c(` kick g module <name> Full DDD module (controller, DTOs, use-cases, repo)`),c(` kick g scaffold <n> <f..> CRUD module from field definitions`),c(` kick g controller <name> Standalone controller`),c(` kick g service <name> @Service() class`),c(` kick g middleware <name> Express middleware`),c(` kick g guard <name> Route guard (auth, roles, etc.)`),c(` kick g adapter <name> AppAdapter with lifecycle hooks`),c(` kick g dto <name> Zod DTO schema`),i===`cqrs`&&c(` kick g job <name> Queue job processor`),c(` kick g config Generate kick.config.ts`),c(``),c(`Add packages:`),c(` kick add <pkg> Install a KickJS package + peers`),c(` kick add --list Show all available packages`),c(``),c(`Available: auth, swagger, drizzle, prisma, ws, queue, devtools, mcp, testing`),c(``)}const ht={GET:A.green,POST:A.cyan,PUT:A.yellow,PATCH:A.magenta,DELETE:A.red};function gt(e){return(ht[e]??A.dim)(e.padEnd(7))}function _t(e){let t=`[${e}]`.padEnd(10);switch(e){case`CRITICAL`:return A.red(t);case`WARNING`:return A.yellow(t);case`INFO`:return A.blue(A.dim(t));default:return t}}A.green(`✓`),A.red(`✖`),A.yellow(`⚠`),A.blue(`ℹ`);function vt(e){k.intro(A.bgCyan(A.black(` ${e} `)))}function yt(e){k.outro(e)}function bt(e){k.isCancel(e)&&(k.cancel(`Operation cancelled.`),process.exit(0))}async function xt(e){let t=await k.text(e);return bt(t),t}async function St(e){let t=await k.select(e);return bt(t),t}async function Ct(e){let t=await k.multiselect(e);return bt(t),t}async function F(e){let t=await k.confirm(e);return bt(t),t}function wt(){return k.spinner()}const I=k.log,Tt={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},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`},"db-pg":{pkg:`@forinda/kickjs-db-pg`,peers:[`pg`],description:`kick/db PostgreSQL dialect + adapter (pgDialect, pgAdapter)`},drizzle:{pkg:`@forinda/kickjs-drizzle`,peers:[`drizzle-orm`],description:`Drizzle ORM adapter + query builder`},prisma:{pkg:`@forinda/kickjs-prisma`,peers:[`@prisma/client`],description:`Prisma adapter + query builder`},ws:{pkg:`@forinda/kickjs-ws`,peers:[`socket.io`],description:`WebSocket with @WsController decorators`},devtools:{pkg:`@forinda/kickjs-devtools`,peers:[],description:`Development dashboard — routes, DI, metrics, health`,dev:!0},auth:{pkg:`@forinda/kickjs-auth`,peers:[`jsonwebtoken`],description:`Authentication — JWT, API key, and custom strategies`},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`},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}};function L(e,t=process.cwd()){let n=t;for(;;){if(g(w(n,e)))return n;let t=x(n);if(t===n)return null;n=t}}function Et(){return L(`pnpm-lock.yaml`)?`pnpm`:L(`yarn.lock`)?`yarn`:L(`bun.lockb`)||L(`bun.lock`)?`bun`:L(`package-lock.json`)?`npm`:null}function Dt(){let e=process.cwd();for(;e;){let t=w(e,`package.json`);if(g(t))try{let e=JSON.parse(v(t,`utf-8`)).packageManager;if(typeof e==`string`){let t=e.split(`@`)[0];if(i.includes(t))return t}}catch{}let n=x(e);if(n===e)return null;e=n}return null}async function Ot(e){if(e&&i.includes(e))return{pm:e,source:`flag`};let t=await r(process.cwd());if(t?.packageManager&&i.includes(t.packageManager))return{pm:t.packageManager,source:`config`};let n=Dt();if(n)return{pm:n,source:`package.json`};let a=Et();return a?{pm:a,source:`lockfile`}:{pm:`npm`,source:`default`}}async function kt(e){let{pm:t}=await Ot(e);return t}function At(e=!1){let t=Object.entries(Tt),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(`, `)})`:``;return` ${r} ${t.description}${i}`};console.log(`
1192
1198
  Core packages (always installed by \`kick new\`):
1193
1199
  `);for(let e of r)console.log(a(e));if(e){console.log(`
1194
1200
  Optional packages (add as needed):
1195
1201
  `);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(`
1196
- Usage: kick add auth drizzle swagger`),console.log(` kick add queue:bullmq`),console.log()}function Et(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=>{Tt(!!e.all)})}function Dt(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){Tt(!!t.all);return}let{pm:n,source:r}=await Ct(t.pm);console.log(`\n Using ${n} (resolved from ${r})`);let i=t.dev,a=new Set,o=new Set,s=[];for(let t of e){let e=bt[t];if(!e){s.push(t);continue}let n=i||e.dev?o:a;n.add(e.pkg);for(let t of e.peers)n.add(t)}if(!(s.length>0&&(console.log(`\n Unknown packages: ${s.join(`, `)}`),console.log(` Run "kick add --list" to see available packages.
1197
- `),a.size===0&&o.size===0))){if(a.size>0){let e=Array.from(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{T(t,{stdio:`inherit`})}catch{console.log(`\n Installation failed. Run manually:\n ${t}\n`)}}if(o.size>0){let e=Array.from(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{T(t,{stdio:`inherit`})}catch{console.log(`\n Installation failed. Run manually:\n ${t}\n`)}}console.log(` Done!
1198
- `)}})}const Ot=[{value:`auth`,label:`Auth`,hint:`JWT, OAuth, API keys`},{value:`swagger`,label:`Swagger`,hint:`OpenAPI docs`},{value:`ws`,label:`WebSocket`,hint:`rooms, heartbeat`},{value:`queue`,label:`Queue`,hint:`BullMQ/RabbitMQ/Kafka`},{value:`devtools`,label:`DevTools`,hint:`debug dashboard`}];function kt(e){e.command(`new [name]`).alias(`init`).description(`Create a new KickJS project (use "." for current directory)`).option(`-d, --directory <dir>`,`Target directory (defaults to project name)`).option(`--pm <manager>`,`Package manager: pnpm | npm | yarn | bun`).option(`--git`,`Initialize git repository`).option(`--no-git`,`Skip git initialization`).option(`--install`,`Install dependencies after scaffolding`).option(`--no-install`,`Skip dependency installation`).option(`-f, --force`,`Remove existing files without prompting`).option(`-t, --template <type>`,`Project template: rest | ddd | cqrs | minimal`).option(`-r, --repo <type>`,`Default repository: prisma | drizzle | inmemory | custom`).option(`--packages <packages>`,`Comma-separated packages to include (e.g. auth,swagger,ws,queue)`).option(`-y, --yes`,`Pick safe defaults for every prompt (template=minimal, repo=inmemory, no extras, git+install on)`).option(`--non-interactive`,`alias for --yes`).action(async(e,t)=>{mt(`KickJS — Create a new project`);let n=!!(t.yes||t.nonInteractive);e||=n?`my-api`:await gt({message:`Project name`,placeholder:`my-api`,defaultValue:`my-api`});let r;if(e===`.`?(r=C(`.`),e=re(r)):r=C(t.directory||e),h(r)){let i=ee(r);if(i.length>0){if(t.force)I.warn(`Clearing existing files in ${r}`);else if(n){I.warn(`Directory "${e}" is not empty. Pass --force to clear it.`),P(`Aborted.`);return}else{I.warn(`Directory "${e}" is not empty:`);let t=i.slice(0,5);for(let e of t)I.message(` - ${e}`);if(i.length>5&&I.message(` ... and ${i.length-5} more`),!await F({message:k.red(`Remove all existing files and proceed?`),initialValue:!1})){P(`Aborted.`);return}}for(let e of i)v(C(r,e),{recursive:!0,force:!0})}}let i=t.template;i||=n?`minimal`:await _t({message:`Project template`,options:[{value:`rest`,label:`REST API`,hint:`Express + Swagger`},{value:`ddd`,label:`DDD`,hint:`Domain-Driven Design modules`},{value:`cqrs`,label:`CQRS`,hint:`Commands, Queries, Events + WS/Queue`},{value:`minimal`,label:`Minimal`,hint:`bare Express`}]});let a=t.pm;a||=n?await wt(void 0):await _t({message:`Package manager`,options:[{value:`pnpm`,label:`pnpm`},{value:`npm`,label:`npm`},{value:`yarn`,label:`yarn`},{value:`bun`,label:`bun`}]});let o=t.repo;o||(n?o=`inmemory`:(o=await _t({message:`Default repository/ORM`,options:[{value:`prisma`,label:`Prisma`},{value:`drizzle`,label:`Drizzle`},{value:`inmemory`,label:`In-Memory`},{value:`custom`,label:`Custom`,hint:`specify later`}]}),o===`custom`&&(o=await gt({message:`Custom repository name`,defaultValue:`custom`}))));let s;if(t.packages!==void 0){let e=t.packages.trim().toLowerCase();s=e===``||e===`none`||e===`false`?[]:t.packages.split(`,`).map(e=>e.trim()).filter(Boolean)}else s=n?[]:await vt({message:`Select packages to include`,options:[...Ot],required:!1});let c;c=t.git===void 0?n?!0:await F({message:`Initialize git repository?`,initialValue:!0}):t.git;let l;l=t.install===void 0?n?!0:await F({message:`Install dependencies?`,initialValue:!0}):t.install,await ut({name:e,directory:r,packageManager:a,initGit:c,installDeps:l,template:i,defaultRepo:o,packages:s}),P(`Done! Next steps: ${k.cyan(`cd ${e} && ${a} dev`)}`)})}function R(e){return e.replace(/[-_\s]+(.)?/g,(e,t)=>t?t.toUpperCase():``).replace(/^(.)/,e=>e.toUpperCase())}function z(e){let t=R(e);return t.charAt(0).toLowerCase()+t.slice(1)}function B(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}function V(e){return _e.plural(e)}function At(e){return _e.plural(e)}function jt(e){return B(e).replace(/-/g,`_`)}function Mt(e){let t=e.cwd??process.cwd(),n=e.pluralize??!0,r=R(e.name),i=z(e.name),a=B(e.name),o=jt(e.name),s={name:e.name,pascal:r,camel:i,kebab:a,snake:o,modulesDir:e.modulesDir??`src/modules`,cwd:t,args:e.args??[],flags:e.flags??{}};if(n){let e=V(a);s.pluralKebab=e,s.pluralPascal=R(e),s.pluralCamel=z(e)}return s}function Nt(e,t){return C(e.cwd,t)}async function Pt(e){return import(w(e).href)}const Ft=new Map;async function It(e){let t=Ft.get(e);if(t)return t;let n=Lt(e);return Ft.set(e,n),n}async function Lt(e){let t=C(e,`package.json`);if(!h(t))return{generators:[],loaded:[],failed:[]};let n=Rt(JSON.parse(await E(t,`utf-8`))),r=p(C(e,`package.json`)),i=[],a=[],o=[];for(let e of n){let t;try{t=r.resolve(`${e}/package.json`)}catch{continue}let n;try{n=JSON.parse(await E(t,`utf-8`))}catch(t){o.push({source:e,reason:`failed to parse package.json: ${t}`});continue}if(!n.kickjs?.generators)continue;let s=n.kickjs.generators,c=C(b(t),s);if(!h(c)){o.push({source:e,reason:`kickjs.generators points to missing file: ${s}`});continue}let l;try{l=await Pt(c)}catch(t){o.push({source:e,reason:`failed to import manifest: ${t}`});continue}let u=l.default;if(!Array.isArray(u)){o.push({source:e,reason:`manifest's default export is not an array of GeneratorSpec`});continue}for(let t of u){if(!zt(t)){o.push({source:e,reason:`manifest entry is not a valid GeneratorSpec (missing name/files)`});continue}i.push({source:e,spec:t})}a.push(e)}return{generators:i,loaded:a,failed:o}}function Rt(e){let t=new Set;for(let n of[e.dependencies,e.devDependencies,e.peerDependencies])if(n)for(let e of Object.keys(n))t.add(e);return Array.from(t)}function zt(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function Bt(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return Ut(r.spec,r.source,e,n);let i=Ht(await It(n),e.generatorName);return i?Ut(i.spec,i.source,e,n):null}async function Vt(e,t=[]){let n=await It(e),r=new Set(t.map(e=>e.spec.name)),i=n.generators.filter(e=>!r.has(e.spec.name));return{generators:[...t,...i],loaded:n.loaded,failed:n.failed}}function Ht(e,t){return e.generators.find(e=>e.spec.name===t)}async function Ut(e,t,n,r){let i=Mt({name:n.itemName,args:n.args,flags:n.flags,modulesDir:n.modulesDir,pluralize:n.pluralize,cwd:r}),a=await e.files(i),o=[];for(let e of a){let t=Nt(i,e.path);await j(t,e.content),o.push(t)}return{files:o,source:t}}const Wt={inmemory:`in-memory`,drizzle:`Drizzle`,prisma:`Prisma`};function Gt(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function Kt(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).toLowerCase()}function qt(e){return Wt[e]??Gt(e)}function Jt(e,t,n){let r={inmemory:`InMemory${e}Repository`,drizzle:`Drizzle${e}Repository`,prisma:`Prisma${e}Repository`},i={inmemory:`in-memory-${t}`,drizzle:`drizzle-${t}`,prisma:`prisma-${t}`};return{repoClass:r[n]??`${Gt(n)}${e}Repository`,repoFile:i[n]??`${Kt(n)}-${t}`}}function Yt(e){return e??`define`}function Xt(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,{repoClass:o,repoFile:s}=Jt(t,n,i),c=Yt(a),l=`/**
1202
+ Usage: kick add auth drizzle swagger`),console.log(` kick add queue:bullmq`),console.log()}function jt(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=>{At(!!e.all)})}function Mt(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){At(!!t.all);return}let{pm:n,source:r}=await Ot(t.pm);console.log(`\n Using ${n} (resolved from ${r})`);let i=t.dev,a=new Set,o=new Set,s=[];for(let t of e){let e=Tt[t];if(!e){s.push(t);continue}let n=i||e.dev?o:a;n.add(e.pkg);for(let t of e.peers)n.add(t)}if(!(s.length>0&&(console.log(`\n Unknown packages: ${s.join(`, `)}`),console.log(` Run "kick add --list" to see available packages.
1203
+ `),a.size===0&&o.size===0))){if(a.size>0){let e=Array.from(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{E(t,{stdio:`inherit`})}catch{console.log(`\n Installation failed. Run manually:\n ${t}\n`)}}if(o.size>0){let e=Array.from(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{E(t,{stdio:`inherit`})}catch{console.log(`\n Installation failed. Run manually:\n ${t}\n`)}}console.log(` Done!
1204
+ `)}})}const Nt=[{value:`auth`,label:`Auth`,hint:`JWT, OAuth, API keys`},{value:`swagger`,label:`Swagger`,hint:`OpenAPI docs`},{value:`ws`,label:`WebSocket`,hint:`rooms, heartbeat`},{value:`queue`,label:`Queue`,hint:`BullMQ/RabbitMQ/Kafka`},{value:`devtools`,label:`DevTools`,hint:`debug dashboard`}];function Pt(e){e.command(`new [name]`).alias(`init`).description(`Create a new KickJS project (use "." for current directory)`).option(`-d, --directory <dir>`,`Target directory (defaults to project name)`).option(`--pm <manager>`,`Package manager: pnpm | npm | yarn | bun`).option(`--git`,`Initialize git repository`).option(`--no-git`,`Skip git initialization`).option(`--install`,`Install dependencies after scaffolding`).option(`--no-install`,`Skip dependency installation`).option(`-f, --force`,`Remove existing files without prompting`).option(`-t, --template <type>`,`Project template: rest | ddd | cqrs | minimal`).option(`-r, --repo <type>`,`Default repository: prisma | drizzle | inmemory | custom`).option(`--packages <packages>`,`Comma-separated packages to include (e.g. auth,swagger,ws,queue)`).option(`-y, --yes`,`Pick safe defaults for every prompt (template=minimal, repo=inmemory, no extras, git+install on)`).option(`--non-interactive`,`alias for --yes`).action(async(e,t)=>{vt(`KickJS — Create a new project`);let n=!!(t.yes||t.nonInteractive);e||=n?`my-api`:await xt({message:`Project name`,placeholder:`my-api`,defaultValue:`my-api`});let r;if(e===`.`?(r=w(`.`),e=re(r)):r=w(t.directory||e),g(r)){let i=y(r);if(i.length>0){if(t.force)I.warn(`Clearing existing files in ${r}`);else if(n){I.warn(`Directory "${e}" is not empty. Pass --force to clear it.`),yt(`Aborted.`);return}else{I.warn(`Directory "${e}" is not empty:`);let t=i.slice(0,5);for(let e of t)I.message(` - ${e}`);if(i.length>5&&I.message(` ... and ${i.length-5} more`),!await F({message:A.red(`Remove all existing files and proceed?`),initialValue:!1})){yt(`Aborted.`);return}}for(let e of i)ee(w(r,e),{recursive:!0,force:!0})}}let i=t.template;i||=n?`minimal`:await St({message:`Project template`,options:[{value:`rest`,label:`REST API`,hint:`Express + Swagger`},{value:`ddd`,label:`DDD`,hint:`Domain-Driven Design modules`},{value:`cqrs`,label:`CQRS`,hint:`Commands, Queries, Events + WS/Queue`},{value:`minimal`,label:`Minimal`,hint:`bare Express`}]});let a=t.pm;a||=n?await kt(void 0):await St({message:`Package manager`,options:[{value:`pnpm`,label:`pnpm`},{value:`npm`,label:`npm`},{value:`yarn`,label:`yarn`},{value:`bun`,label:`bun`}]});let o=t.repo;o||(n?o=`inmemory`:(o=await St({message:`Default repository/ORM`,options:[{value:`prisma`,label:`Prisma`},{value:`drizzle`,label:`Drizzle`},{value:`inmemory`,label:`In-Memory`},{value:`custom`,label:`Custom`,hint:`specify later`}]}),o===`custom`&&(o=await xt({message:`Custom repository name`,defaultValue:`custom`}))));let s;if(t.packages!==void 0){let e=t.packages.trim().toLowerCase();s=e===``||e===`none`||e===`false`?[]:t.packages.split(`,`).map(e=>e.trim()).filter(Boolean)}else s=n?[]:await Ct({message:`Select packages to include`,options:[...Nt],required:!1});let c;c=t.git===void 0?n?!0:await F({message:`Initialize git repository?`,initialValue:!0}):t.git;let l;l=t.install===void 0?n?!0:await F({message:`Install dependencies?`,initialValue:!0}):t.install,await mt({name:e,directory:r,packageManager:a,initGit:c,installDeps:l,template:i,defaultRepo:o,packages:s}),yt(`Done! Next steps: ${A.cyan(`cd ${e} && ${a} dev`)}`)})}function R(e){return e.replace(/[-_\s]+(.)?/g,(e,t)=>t?t.toUpperCase():``).replace(/^(.)/,e=>e.toUpperCase())}function z(e){let t=R(e);return t.charAt(0).toLowerCase()+t.slice(1)}function B(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}function V(e){return ve.plural(e)}function Ft(e){return ve.plural(e)}function It(e){return B(e).replace(/-/g,`_`)}function Lt(e){let t=e.cwd??process.cwd(),n=e.pluralize??!0,r=R(e.name),i=z(e.name),a=B(e.name),o=It(e.name),s={name:e.name,pascal:r,camel:i,kebab:a,snake:o,modulesDir:e.modulesDir??`src/modules`,cwd:t,args:e.args??[],flags:e.flags??{}};if(n){let e=V(a);s.pluralKebab=e,s.pluralPascal=R(e),s.pluralCamel=z(e)}return s}function Rt(e,t){return w(e.cwd,t)}async function zt(e){return import(T(e).href)}const Bt=new Map;async function Vt(e){let t=Bt.get(e);if(t)return t;let n=Ht(e);return Bt.set(e,n),n}async function Ht(e){let t=w(e,`package.json`);if(!g(t))return{generators:[],loaded:[],failed:[]};let n=Ut(JSON.parse(await D(t,`utf-8`))),r=m(w(e,`package.json`)),i=[],a=[],o=[];for(let e of n){let t;try{t=r.resolve(`${e}/package.json`)}catch{continue}let n;try{n=JSON.parse(await D(t,`utf-8`))}catch(t){o.push({source:e,reason:`failed to parse package.json: ${t}`});continue}if(!n.kickjs?.generators)continue;let s=n.kickjs.generators,c=w(x(t),s);if(!g(c)){o.push({source:e,reason:`kickjs.generators points to missing file: ${s}`});continue}let l;try{l=await zt(c)}catch(t){o.push({source:e,reason:`failed to import manifest: ${t}`});continue}let u=l.default;if(!Array.isArray(u)){o.push({source:e,reason:`manifest's default export is not an array of GeneratorSpec`});continue}for(let t of u){if(!Wt(t)){o.push({source:e,reason:`manifest entry is not a valid GeneratorSpec (missing name/files)`});continue}i.push({source:e,spec:t})}a.push(e)}return{generators:i,loaded:a,failed:o}}function Ut(e){let t=new Set;for(let n of[e.dependencies,e.devDependencies,e.peerDependencies])if(n)for(let e of Object.keys(n))t.add(e);return Array.from(t)}function Wt(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function Gt(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return Jt(r.spec,r.source,e,n);let i=qt(await Vt(n),e.generatorName);return i?Jt(i.spec,i.source,e,n):null}async function Kt(e,t=[]){let n=await Vt(e),r=new Set(t.map(e=>e.spec.name)),i=n.generators.filter(e=>!r.has(e.spec.name));return{generators:[...t,...i],loaded:n.loaded,failed:n.failed}}function qt(e,t){return e.generators.find(e=>e.spec.name===t)}async function Jt(e,t,n,r){let i=Lt({name:n.itemName,args:n.args,flags:n.flags,modulesDir:n.modulesDir,pluralize:n.pluralize,cwd:r}),a=await e.files(i),o=[];for(let e of a){let t=Rt(i,e.path);await M(t,e.content),o.push(t)}return{files:o,source:t}}function H(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}const Yt={inmemory:`in-memory`,drizzle:`Drizzle`,prisma:`Prisma`};function Xt(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function Zt(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).toLowerCase()}function Qt(e){return Yt[e]??Xt(e)}function $t(e,t,n){let r={inmemory:`InMemory${e}Repository`,drizzle:`Drizzle${e}Repository`,prisma:`Prisma${e}Repository`},i={inmemory:`in-memory-${t}`,drizzle:`drizzle-${t}`,prisma:`prisma-${t}`};return{repoClass:r[n]??`${Xt(n)}${e}Repository`,repoFile:i[n]??`${Zt(n)}-${t}`}}function en(e){return e??`define`}function tn(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,{repoClass:o,repoFile:s}=$t(t,n,i),c=en(a),l=`/**
1199
1205
  * ${t} Module
1200
1206
  *
1201
1207
  * Self-contained feature module following Domain-Driven Design (DDD).
@@ -1205,7 +1211,7 @@ description: Patterns to refuse outright when the user asks for them — they br
1205
1211
  * presentation/ — HTTP controllers (entry points)
1206
1212
  * application/ — Use cases (orchestration) and DTOs (validation)
1207
1213
  * domain/ — Entities, value objects, repository interfaces, domain services
1208
- * infrastructure/ — Repository implementations (currently ${qt(i)})
1214
+ * infrastructure/ — Repository implementations (currently ${Qt(i)})
1209
1215
  */`,u=`import { ${t.toUpperCase()}_REPOSITORY } from './domain/repositories/${n}.repository'
1210
1216
  import { ${o} } from './infrastructure/repositories/${s}.repository'
1211
1217
  import { ${t}Controller } from './presentation/${n}.controller'
@@ -1215,17 +1221,17 @@ import.meta.glob(
1215
1221
  ['./domain/services/**/*.ts', './application/use-cases/**/*.ts', '!./**/*.test.ts'],
1216
1222
  { eager: true },
1217
1223
  )`,d=` /**
1218
- * Declare HTTP routes for this module.
1224
+ * Declare HTTP routes for this module. Return value shape:
1219
1225
  *
1220
- * The path is prefixed with the global apiPrefix and version
1221
- * (e.g. /api/v1/${r}). The framework derives the Express
1222
- * Router from the controller via \`buildRoutes()\` and uses the
1223
- * same controller for OpenAPI spec generation via SwaggerAdapter.
1226
+ * - \`path\` — URL prefix for this route set, mounted under
1227
+ * \`/{apiPrefix}/v{version}{path}\`.
1228
+ * - \`controller\` — Controller class. Used both for the route
1229
+ * handler bindings and OpenAPI spec generation.
1230
+ * - \`version\` — Optional. Overrides the app-wide API version
1231
+ * for this route set only.
1224
1232
  *
1225
1233
  * Return an **array** to mount multiple route sets under the
1226
- * same module (e.g. side-by-side v1 + v2 controllers). Each
1227
- * entry can override the API version with a \`version\` field —
1228
- * the mount path becomes \`/{apiPrefix}/v{version}{path}\`:
1234
+ * same module (e.g. side-by-side v1 + v2 controllers):
1229
1235
  *
1230
1236
  * return [
1231
1237
  * { path: '/${r}', version: 1, controller: ${t}V1Controller },
@@ -1239,7 +1245,7 @@ export class ${t}Module implements AppModule {
1239
1245
  /**
1240
1246
  * Register module dependencies in the DI container.
1241
1247
  * Bind repository interface tokens to their implementations here.
1242
- * Currently wired to ${qt(i)}. To swap implementations, change the factory target.
1248
+ * Currently wired to ${Qt(i)}. To swap implementations, change the factory target.
1243
1249
  */
1244
1250
  register(container: Container): void {
1245
1251
  container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
@@ -1265,7 +1271,7 @@ export const ${t}Module = defineModule({
1265
1271
  /**
1266
1272
  * Register module dependencies in the DI container.
1267
1273
  * Bind repository interface tokens to their implementations here.
1268
- * Currently wired to ${qt(i)}. To swap implementations, change the factory target.
1274
+ * Currently wired to ${Qt(i)}. To swap implementations, change the factory target.
1269
1275
  */
1270
1276
  register(container) {
1271
1277
  container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
@@ -1282,7 +1288,7 @@ ${d}
1282
1288
  },
1283
1289
  }),
1284
1290
  })
1285
- `}function Zt(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,{repoClass:o,repoFile:s}=Jt(t,n,i),c=Yt(a),l=`/**
1291
+ `}function nn(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,{repoClass:o,repoFile:s}=$t(t,n,i),c=en(a),l=`/**
1286
1292
  * ${t} Module
1287
1293
  *
1288
1294
  * REST module with a flat folder structure.
@@ -1300,15 +1306,14 @@ import { ${t}Controller } from './${n}.controller'
1300
1306
 
1301
1307
  // Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container
1302
1308
  import.meta.glob(['./**/*.service.ts', './**/*.repository.ts', '!./**/*.test.ts'], { eager: true })`,d=` /**
1303
- * Declare HTTP routes for this module.
1309
+ * Declare HTTP routes for this module. Return value shape:
1304
1310
  *
1305
- * Pass \`controller\` and the framework derives the Express
1306
- * Router via \`buildRoutes()\` and uses the same controller for
1307
- * OpenAPI spec generation through SwaggerAdapter.
1311
+ * - \`path\` URL prefix for this route set.
1312
+ * - \`controller\` Controller class (also drives OpenAPI).
1313
+ * - \`version\` — Optional. Overrides the app-wide API version.
1308
1314
  *
1309
- * Return an **array** to mount multiple route sets under the
1310
- * same module (side-by-side v1 + v2 controllers, admin surfaces).
1311
- * Each entry can override the API version with a \`version\` field:
1315
+ * Return an **array** to mount multiple route sets admin
1316
+ * surfaces, side-by-side v1 + v2 controllers, etc:
1312
1317
  *
1313
1318
  * return [
1314
1319
  * { path: '/${r}', version: 1, controller: ${t}V1Controller },
@@ -1355,11 +1360,14 @@ ${d}
1355
1360
  },
1356
1361
  }),
1357
1362
  })
1358
- `}function Qt(e){let{pascal:t,kebab:n,plural:r=``,style:i}=e,a=Yt(i),o=` /**
1359
- * Pass \`controller\` and the framework derives the Express
1360
- * Router via \`buildRoutes()\`. Return an array to mount multiple
1361
- * route sets each entry can override the API version with a
1362
- * \`version\` field:
1363
+ `}function rn(e){let{pascal:t,kebab:n,plural:r=``,style:i}=e,a=en(i),o=` /**
1364
+ * Declare HTTP routes. Return value shape:
1365
+ *
1366
+ * - \`path\` URL prefix for this route set.
1367
+ * - \`controller\` Controller class (also drives OpenAPI).
1368
+ * - \`version\` — Optional. Overrides the app-wide API version.
1369
+ *
1370
+ * Return an array to mount multiple route sets:
1363
1371
  *
1364
1372
  * return [
1365
1373
  * { path: '/${r}', version: 1, controller: ${t}V1Controller },
@@ -1392,7 +1400,7 @@ ${o}
1392
1400
  },
1393
1401
  }),
1394
1402
  })
1395
- `}function $t(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
1403
+ `}function an(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
1396
1404
  import { ApiTags } from '@forinda/kickjs-swagger'
1397
1405
  import { Create${t}UseCase } from '../application/use-cases/create-${n}.use-case'
1398
1406
  import { Get${t}UseCase } from '../application/use-cases/get-${n}.use-case'
@@ -1455,7 +1463,7 @@ export class ${t}Controller {
1455
1463
  ctx.noContent()
1456
1464
  }
1457
1465
  }
1458
- `}function en(e){let{pascal:t,kebab:n}=e,r=t.charAt(0).toLowerCase()+t.slice(1);return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
1466
+ `}function on(e){let{pascal:t,kebab:n}=e,r=t.charAt(0).toLowerCase()+t.slice(1);return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
1459
1467
  import { ApiTags } from '@forinda/kickjs-swagger'
1460
1468
  import { ${t}Service } from './${n}.service'
1461
1469
  import { create${t}Schema } from './dtos/create-${n}.dto'
@@ -1510,14 +1518,14 @@ export class ${t}Controller {
1510
1518
  ctx.noContent()
1511
1519
  }
1512
1520
  }
1513
- `}function tn(e){let{pascal:t}=e;return`import type { QueryParamsConfig } from '@forinda/kickjs'
1521
+ `}function sn(e){let{pascal:t}=e;return`import type { QueryParamsConfig } from '@forinda/kickjs'
1514
1522
 
1515
1523
  export const ${t.toUpperCase()}_QUERY_CONFIG: QueryParamsConfig = {
1516
1524
  filterable: ['name'],
1517
1525
  sortable: ['name', 'createdAt'],
1518
1526
  searchable: ['name'],
1519
1527
  }
1520
- `}function nn(e){let{pascal:t}=e;return`import { z } from 'zod'
1528
+ `}function cn(e){let{pascal:t}=e;return`import { z } from 'zod'
1521
1529
 
1522
1530
  /**
1523
1531
  * Create ${t} DTO — Zod schema for validating POST request bodies.
@@ -1533,20 +1541,20 @@ export const create${t}Schema = z.object({
1533
1541
  })
1534
1542
 
1535
1543
  export type Create${t}DTO = z.infer<typeof create${t}Schema>
1536
- `}function rn(e){let{pascal:t}=e;return`import { z } from 'zod'
1544
+ `}function ln(e){let{pascal:t}=e;return`import { z } from 'zod'
1537
1545
 
1538
1546
  export const update${t}Schema = z.object({
1539
1547
  name: z.string().min(1).max(200).optional(),
1540
1548
  })
1541
1549
 
1542
1550
  export type Update${t}DTO = z.infer<typeof update${t}Schema>
1543
- `}function an(e){let{pascal:t}=e;return`export interface ${t}ResponseDTO {
1551
+ `}function un(e){let{pascal:t}=e;return`export interface ${t}ResponseDTO {
1544
1552
  id: string
1545
1553
  name: string
1546
1554
  createdAt: string
1547
1555
  updatedAt: string
1548
1556
  }
1549
- `}function on(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return[{file:`create-${n}.use-case.ts`,content:`/**
1557
+ `}function dn(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return[{file:`create-${n}.use-case.ts`,content:`/**
1550
1558
  * Create ${t} Use Case
1551
1559
  *
1552
1560
  * Application layer — orchestrates a single business operation.
@@ -1624,7 +1632,7 @@ export class Delete${t}UseCase {
1624
1632
  await this.repo.delete(id)
1625
1633
  }
1626
1634
  }
1627
- `}]}function sn(e){let{pascal:t,kebab:n,dtoPrefix:r=`../../application/dtos`,tokenScope:i=`app`}=e;return`/**
1635
+ `}]}function fn(e){let{pascal:t,kebab:n,dtoPrefix:r=`../../application/dtos`,tokenScope:i=`app`}=e;return`/**
1628
1636
  * ${t} Repository Interface
1629
1637
  *
1630
1638
  * Defines the contract for data access.
@@ -1659,7 +1667,7 @@ export interface I${t}Repository {
1659
1667
  * adopters must NOT use the reserved \`'kick/'\` namespace.
1660
1668
  */
1661
1669
  export const ${t.toUpperCase()}_REPOSITORY = createToken<I${t}Repository>('${i}/${t}/repository')
1662
- `}function H(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e;return`/**
1670
+ `}function U(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e;return`/**
1663
1671
  * In-Memory ${t} Repository
1664
1672
  *
1665
1673
  * Implements the repository interface using a Map.
@@ -1719,7 +1727,7 @@ export class InMemory${t}Repository implements I${t}Repository {
1719
1727
  this.store.delete(id)
1720
1728
  }
1721
1729
  }
1722
- `}function cn(e){let{pascal:t,kebab:n,repoType:r=``,repoPrefix:i=`../../domain/repositories`,dtoPrefix:a=`../../application/dtos`}=e,o=r.charAt(0).toUpperCase()+r.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase());return`/**
1730
+ `}function pn(e){let{pascal:t,kebab:n,repoType:r=``,repoPrefix:i=`../../domain/repositories`,dtoPrefix:a=`../../application/dtos`}=e,o=r.charAt(0).toUpperCase()+r.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase());return`/**
1723
1731
  * ${o} ${t} Repository
1724
1732
  *
1725
1733
  * Stub implementation for a custom '${r}' repository.
@@ -1788,7 +1796,7 @@ export class ${o}${t}Repository implements I${t}Repository {
1788
1796
  this.store.delete(id)
1789
1797
  }
1790
1798
  }
1791
- `}function ln(e){let{pascal:t,kebab:n}=e;return`/**
1799
+ `}function mn(e){let{pascal:t,kebab:n}=e;return`/**
1792
1800
  * ${t} Domain Service
1793
1801
  *
1794
1802
  * Domain layer — contains business rules that don't belong to a single entity.
@@ -1811,7 +1819,7 @@ export class ${t}DomainService {
1811
1819
  }
1812
1820
  }
1813
1821
  }
1814
- `}function un(e){let{pascal:t,kebab:n}=e;return`/**
1822
+ `}function hn(e){let{pascal:t,kebab:n}=e;return`/**
1815
1823
  * ${t} Entity
1816
1824
  *
1817
1825
  * Domain layer — the core business object.
@@ -1880,7 +1888,7 @@ export class ${t} {
1880
1888
  }
1881
1889
  }
1882
1890
  }
1883
- `}function dn(e){let{pascal:t}=e;return`/**
1891
+ `}function gn(e){let{pascal:t}=e;return`/**
1884
1892
  * ${t} ID Value Object
1885
1893
  *
1886
1894
  * Domain layer — wraps a primitive ID with type safety and validation.
@@ -1914,7 +1922,7 @@ export class ${t}Id {
1914
1922
  return this.value === other.value
1915
1923
  }
1916
1924
  }
1917
- `}function fn(e){let{pascal:t,kebab:n,plural:r=``}=e;return`import { describe, it, expect, beforeEach } from 'vitest'
1925
+ `}function _n(e){let{pascal:t,kebab:n,plural:r=``}=e;return`import { describe, it, expect, beforeEach } from 'vitest'
1918
1926
  import { Container } from '@forinda/kickjs'
1919
1927
 
1920
1928
  describe('${t}Controller', () => {
@@ -1966,7 +1974,7 @@ describe('${t}Controller', () => {
1966
1974
  })
1967
1975
  })
1968
1976
  })
1969
- `}function pn(e){let{pascal:t,kebab:n,plural:r=``,repoPrefix:i=`../infrastructure/repositories/in-memory-${n}.repository`}=e;return`import { describe, it, expect, beforeEach } from 'vitest'
1977
+ `}function vn(e){let{pascal:t,kebab:n,plural:r=``,repoPrefix:i=`../infrastructure/repositories/in-memory-${n}.repository`}=e;return`import { describe, it, expect, beforeEach } from 'vitest'
1970
1978
  import { InMemory${t}Repository } from '${i}'
1971
1979
 
1972
1980
  describe('InMemory${t}Repository', () => {
@@ -2028,7 +2036,7 @@ describe('InMemory${t}Repository', () => {
2028
2036
  expect(found).toBeNull()
2029
2037
  })
2030
2038
  })
2031
- `}function mn(e){let{pascal:t,kebab:n}=e;return`import { Service, Inject, HttpException } from '@forinda/kickjs'
2039
+ `}function yn(e){let{pascal:t,kebab:n}=e;return`import { Service, Inject, HttpException } from '@forinda/kickjs'
2032
2040
  import type { ParsedQuery } from '@forinda/kickjs'
2033
2041
  import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from './${n}.repository'
2034
2042
  import type { ${t}ResponseDTO } from './dtos/${n}-response.dto'
@@ -2065,14 +2073,14 @@ export class ${t}Service {
2065
2073
  await this.repo.delete(id)
2066
2074
  }
2067
2075
  }
2068
- `}function hn(e){let{pascal:t}=e;return`import type { QueryFieldConfig } from '@forinda/kickjs'
2076
+ `}function bn(e){let{pascal:t}=e;return`import type { QueryFieldConfig } from '@forinda/kickjs'
2069
2077
 
2070
2078
  export const ${t.toUpperCase()}_QUERY_CONFIG: QueryFieldConfig = {
2071
2079
  filterable: ['name'],
2072
2080
  sortable: ['name', 'createdAt'],
2073
2081
  searchable: ['name'],
2074
2082
  }
2075
- `}function gn(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,o={inmemory:`InMemory${t}Repository`,drizzle:`Drizzle${t}Repository`,prisma:`Prisma${t}Repository`},s={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},c=o[i]??o.inmemory,l=s[i]??s.inmemory,u=a??`define`,d=`/**
2083
+ `}function xn(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,o={inmemory:`InMemory${t}Repository`,drizzle:`Drizzle${t}Repository`,prisma:`Prisma${t}Repository`},s={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},c=o[i]??o.inmemory,l=s[i]??s.inmemory,u=a??`define`,d=`/**
2076
2084
  * ${t} Module — CQRS Pattern
2077
2085
  *
2078
2086
  * Separates read (queries) and write (commands) operations.
@@ -2098,11 +2106,13 @@ import.meta.glob(
2098
2106
  ],
2099
2107
  { eager: true },
2100
2108
  )`,p=` /**
2101
- * Declare HTTP routes. Pass \`controller\` and the framework
2102
- * derives the Express Router via \`buildRoutes()\` and uses the
2103
- * same controller for OpenAPI spec generation. Return an array
2104
- * to mount multiple route sets each entry can override the API
2105
- * version with a \`version\` field:
2109
+ * Declare HTTP routes for this CQRS module. Return value shape:
2110
+ *
2111
+ * - \`path\` — URL prefix for this route set.
2112
+ * - \`controller\` Controller class (also drives OpenAPI).
2113
+ * - \`version\` — Optional. Overrides the app-wide API version.
2114
+ *
2115
+ * Return an array to mount multiple route sets:
2106
2116
  *
2107
2117
  * return [
2108
2118
  * { path: '/${r}', version: 1, controller: ${t}V1Controller },
@@ -2149,7 +2159,7 @@ ${p}
2149
2159
  },
2150
2160
  }),
2151
2161
  })
2152
- `}function _n(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
2162
+ `}function Sn(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
2153
2163
  import { ApiTags } from '@forinda/kickjs-swagger'
2154
2164
  import { Create${t}Command } from './commands/create-${n}.command'
2155
2165
  import { Update${t}Command } from './commands/update-${n}.command'
@@ -2212,7 +2222,7 @@ export class ${t}Controller {
2212
2222
  ctx.noContent()
2213
2223
  }
2214
2224
  }
2215
- `}function vn(e){let{pascal:t,kebab:n}=e;return[{file:`create-${n}.command.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
2225
+ `}function Cn(e){let{pascal:t,kebab:n}=e;return[{file:`create-${n}.command.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
2216
2226
  import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../${n}.repository'
2217
2227
  import type { Create${t}DTO } from '../dtos/create-${n}.dto'
2218
2228
  import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
@@ -2266,7 +2276,7 @@ export class Delete${t}Command {
2266
2276
  this.events.emit('${n}.deleted', { id })
2267
2277
  }
2268
2278
  }
2269
- `}]}function yn(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return[{file:`get-${n}.query.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
2279
+ `}]}function wn(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return[{file:`get-${n}.query.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
2270
2280
  import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../${n}.repository'
2271
2281
  import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
2272
2282
 
@@ -2294,7 +2304,7 @@ export class List${i}Query {
2294
2304
  return this.repo.findPaginated(parsed)
2295
2305
  }
2296
2306
  }
2297
- `}]}function bn(e){let{pascal:t,kebab:n}=e;return[{file:`${n}.events.ts`,content:`import { Service } from '@forinda/kickjs'
2307
+ `}]}function Tn(e){let{pascal:t,kebab:n}=e;return[{file:`${n}.events.ts`,content:`import { Service } from '@forinda/kickjs'
2298
2308
  import { EventEmitter } from 'node:events'
2299
2309
  import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
2300
2310
 
@@ -2380,7 +2390,7 @@ export class On${t}ChangeHandler {
2380
2390
  })
2381
2391
  }
2382
2392
  }
2383
- `}]}function xn(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e;return`/**
2393
+ `}]}function En(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e;return`/**
2384
2394
  * Drizzle ${t} Repository
2385
2395
  *
2386
2396
  * Implements the repository interface using Drizzle ORM.
@@ -2462,7 +2472,7 @@ export class Drizzle${t}Repository implements I${t}Repository {
2462
2472
  throw new Error('Drizzle ${t} repository not yet implemented')
2463
2473
  }
2464
2474
  }
2465
- `}function Sn(e){let{pascal:t,kebab:n}=e;return`import type { DrizzleQueryParamsConfig } from '@forinda/kickjs-drizzle'
2475
+ `}function Dn(e){let{pascal:t,kebab:n}=e;return`import type { DrizzleQueryParamsConfig } from '@forinda/kickjs-drizzle'
2466
2476
  // TODO: Import your schema table and reference actual columns for type safety
2467
2477
  // import { ${n}s } from '@/db/schema'
2468
2478
 
@@ -2480,7 +2490,7 @@ export const ${t.toUpperCase()}_QUERY_CONFIG: DrizzleQueryParamsConfig = {
2480
2490
  // ${n}s.name,
2481
2491
  ],
2482
2492
  }
2483
- `}function Cn(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e,a=n.replace(/-([a-z])/g,(e,t)=>t.toUpperCase());return`/**
2493
+ `}function On(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e,a=n.replace(/-([a-z])/g,(e,t)=>t.toUpperCase());return`/**
2484
2494
  * Prisma ${t} Repository
2485
2495
  *
2486
2496
  * Implements the repository interface using Prisma Client.
@@ -2538,7 +2548,7 @@ export class Prisma${t}Repository implements I${t}Repository {
2538
2548
  await this.prisma.${a}.deleteMany({ where: { id } })
2539
2549
  }
2540
2550
  }
2541
- `}async function wn(e){let{pascal:t,kebab:n,plural:r,style:i,write:a}=e;await a(`${n}.module.ts`,Qt({pascal:t,kebab:n,plural:r,style:i})),await a(`${n}.controller.ts`,`import { Controller, Get, type Ctx } from '@forinda/kickjs'
2551
+ `}async function kn(e){let{pascal:t,kebab:n,plural:r,style:i,write:a}=e;await a(`${n}.module.ts`,rn({pascal:t,kebab:n,plural:r,style:i})),await a(`${n}.controller.ts`,`import { Controller, Get, type Ctx } from '@forinda/kickjs'
2542
2552
 
2543
2553
  // \`Ctx<KickRoutes.${t}Controller['<method>']>\` is generated by
2544
2554
  // \`kick typegen\` (auto-run on \`kick dev\`).
@@ -2550,14 +2560,19 @@ export class ${t}Controller {
2550
2560
  ctx.json({ message: '${t} list' })
2551
2561
  }
2552
2562
  }
2553
- `)}async function Tn(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noTests:o,prismaClientPath:s,tokenScope:c,style:l,write:u}=e;await u(`${n}.module.ts`,Zt({pascal:t,kebab:n,plural:r,repo:a,style:l})),await u(`${n}.constants.ts`,hn({pascal:t,kebab:n})),await u(`${n}.controller.ts`,en({pascal:t,kebab:n,plural:r,pluralPascal:i})),await u(`${n}.service.ts`,mn({pascal:t,kebab:n})),await u(`dtos/create-${n}.dto.ts`,nn({pascal:t,kebab:n})),await u(`dtos/update-${n}.dto.ts`,rn({pascal:t,kebab:n})),await u(`dtos/${n}-response.dto.ts`,an({pascal:t,kebab:n})),await u(`${n}.repository.ts`,sn({pascal:t,kebab:n,dtoPrefix:`./dtos`,tokenScope:c}));let d={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},f={inmemory:()=>H({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),drizzle:()=>xn({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),prisma:()=>Cn({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`,prismaClientPath:s})},p=d[a]??`${B(a)}-${n}`,m=f[a]??(()=>cn({pascal:t,kebab:n,repoType:a,repoPrefix:`.`,dtoPrefix:`./dtos`}));await u(`${p}.repository.ts`,m()),o||(a!==`inmemory`&&await u(`in-memory-${n}.repository.ts`,H({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`})),await u(`__tests__/${n}.controller.test.ts`,fn({pascal:t,kebab:n,plural:r})),await u(`__tests__/${n}.repository.test.ts`,pn({pascal:t,kebab:n,plural:r,repoPrefix:`../${d.inmemory??`in-memory-${n}`}.repository`})))}async function En(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noTests:o,prismaClientPath:s,tokenScope:c,style:l,write:u}=e;await u(`${n}.module.ts`,gn({pascal:t,kebab:n,plural:r,repo:a,style:l})),await u(`${n}.constants.ts`,hn({pascal:t,kebab:n})),await u(`${n}.controller.ts`,_n({pascal:t,kebab:n,plural:r,pluralPascal:i})),await u(`dtos/create-${n}.dto.ts`,nn({pascal:t,kebab:n})),await u(`dtos/update-${n}.dto.ts`,rn({pascal:t,kebab:n})),await u(`dtos/${n}-response.dto.ts`,an({pascal:t,kebab:n}));let d=vn({pascal:t,kebab:n});for(let e of d)await u(`commands/${e.file}`,e.content);let f=yn({pascal:t,kebab:n,plural:r,pluralPascal:i});for(let e of f)await u(`queries/${e.file}`,e.content);let p=bn({pascal:t,kebab:n});for(let e of p)await u(`events/${e.file}`,e.content);await u(`${n}.repository.ts`,sn({pascal:t,kebab:n,dtoPrefix:`./dtos`,tokenScope:c}));let m={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},h={inmemory:()=>H({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),drizzle:()=>xn({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),prisma:()=>Cn({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`,prismaClientPath:s})},g=m[a]??`${B(a)}-${n}`,_=h[a]??(()=>cn({pascal:t,kebab:n,repoType:a,repoPrefix:`.`,dtoPrefix:`./dtos`}));await u(`${g}.repository.ts`,_()),o||(a!==`inmemory`&&await u(`in-memory-${n}.repository.ts`,H({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`})),await u(`__tests__/${n}.controller.test.ts`,fn({pascal:t,kebab:n,plural:r})),await u(`__tests__/${n}.repository.test.ts`,pn({pascal:t,kebab:n,plural:r,repoPrefix:`../${m.inmemory??`in-memory-${n}`}.repository`})))}async function Dn(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noEntity:o,noTests:s,prismaClientPath:c,tokenScope:l,style:u,write:d}=e;await d(`${n}.module.ts`,Xt({pascal:t,kebab:n,plural:r,repo:a,style:u})),await d(`constants.ts`,a===`drizzle`?Sn({pascal:t,kebab:n}):tn({pascal:t,kebab:n})),await d(`presentation/${n}.controller.ts`,$t({pascal:t,kebab:n,plural:r,pluralPascal:i})),await d(`application/dtos/create-${n}.dto.ts`,nn({pascal:t,kebab:n})),await d(`application/dtos/update-${n}.dto.ts`,rn({pascal:t,kebab:n})),await d(`application/dtos/${n}-response.dto.ts`,an({pascal:t,kebab:n}));let f=on({pascal:t,kebab:n,plural:r,pluralPascal:i});for(let e of f)await d(`application/use-cases/${e.file}`,e.content);await d(`domain/repositories/${n}.repository.ts`,sn({pascal:t,kebab:n,tokenScope:l})),await d(`domain/services/${n}-domain.service.ts`,ln({pascal:t,kebab:n}));let p={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},m={inmemory:()=>H({pascal:t,kebab:n}),drizzle:()=>xn({pascal:t,kebab:n}),prisma:()=>Cn({pascal:t,kebab:n,prismaClientPath:c})},h=p[a]??`${B(a)}-${n}`,g=m[a]??(()=>cn({pascal:t,kebab:n,repoType:a}));await d(`infrastructure/repositories/${h}.repository.ts`,g()),o||(await d(`domain/entities/${n}.entity.ts`,un({pascal:t,kebab:n})),await d(`domain/value-objects/${n}-id.vo.ts`,dn({pascal:t,kebab:n}))),s||(a!==`inmemory`&&await d(`infrastructure/repositories/in-memory-${n}.repository.ts`,H({pascal:t,kebab:n})),await d(`__tests__/${n}.controller.test.ts`,fn({pascal:t,kebab:n,plural:r})),await d(`__tests__/${n}.repository.test.ts`,pn({pascal:t,kebab:n,plural:r})))}function On(e){return e?typeof e==`string`?e:e.name:`inmemory`}async function kn(e){let{name:t,modulesDir:n,noEntity:r,noTests:i,repo:a=`inmemory`,force:o,dryRun:s}=e,c=e.pluralize!==!1,l=e.pattern??`ddd`;e.minimal&&(l=`minimal`);let u=B(t),d=R(t),f=c?V(u):u,p=c?At(d):d,m=x(n,f),h=[],g=o??!1,_={kebab:u,pascal:d,plural:f,pluralPascal:p,moduleDir:m,repo:a,noEntity:r??!1,noTests:i??!1,prismaClientPath:e.prismaClientPath??`@prisma/client`,tokenScope:e.tokenScope??`app`,style:e.style??`define`,write:async(e,t)=>{let n=x(m,e);if(s){h.push(n);return}if(!g&&await Re(n)&&!await F({message:`File exists: ${k.dim(e)}. Overwrite?`,initialValue:!1})){I.warn(`Skipped: ${e}`);return}await j(n,t),h.push(n)},files:h};switch(l){case`minimal`:await wn(_);break;case`rest`:await Tn(_);break;case`cqrs`:await En(_);break;default:await Dn(_);break}return s||await An(n,d,f,u,_.style),h}async function An(e,t,n,r,i=`define`){let a=x(e,`index.ts`),o=await Re(a),s=`./${n}/${r}.module`,c=i===`class`?`${t}Module`:`${t}Module()`;if(!o){await j(a,`import type { AppModuleEntry } from '@forinda/kickjs'
2563
+ `)}async function An(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noTests:o,prismaClientPath:s,tokenScope:c,style:l,write:u}=e;await u(`${n}.module.ts`,nn({pascal:t,kebab:n,plural:r,repo:a,style:l})),await u(`${n}.constants.ts`,bn({pascal:t,kebab:n})),await u(`${n}.controller.ts`,on({pascal:t,kebab:n,plural:r,pluralPascal:i})),await u(`${n}.service.ts`,yn({pascal:t,kebab:n})),await u(`dtos/create-${n}.dto.ts`,cn({pascal:t,kebab:n})),await u(`dtos/update-${n}.dto.ts`,ln({pascal:t,kebab:n})),await u(`dtos/${n}-response.dto.ts`,un({pascal:t,kebab:n})),await u(`${n}.repository.ts`,fn({pascal:t,kebab:n,dtoPrefix:`./dtos`,tokenScope:c}));let d={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},f={inmemory:()=>U({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),drizzle:()=>En({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),prisma:()=>On({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`,prismaClientPath:s})},p=d[a]??`${B(a)}-${n}`,m=f[a]??(()=>pn({pascal:t,kebab:n,repoType:a,repoPrefix:`.`,dtoPrefix:`./dtos`}));await u(`${p}.repository.ts`,m()),o||(a!==`inmemory`&&await u(`in-memory-${n}.repository.ts`,U({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`})),await u(`__tests__/${n}.controller.test.ts`,_n({pascal:t,kebab:n,plural:r})),await u(`__tests__/${n}.repository.test.ts`,vn({pascal:t,kebab:n,plural:r,repoPrefix:`../${d.inmemory??`in-memory-${n}`}.repository`})))}async function jn(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noTests:o,prismaClientPath:s,tokenScope:c,style:l,write:u}=e;await u(`${n}.module.ts`,xn({pascal:t,kebab:n,plural:r,repo:a,style:l})),await u(`${n}.constants.ts`,bn({pascal:t,kebab:n})),await u(`${n}.controller.ts`,Sn({pascal:t,kebab:n,plural:r,pluralPascal:i})),await u(`dtos/create-${n}.dto.ts`,cn({pascal:t,kebab:n})),await u(`dtos/update-${n}.dto.ts`,ln({pascal:t,kebab:n})),await u(`dtos/${n}-response.dto.ts`,un({pascal:t,kebab:n}));let d=Cn({pascal:t,kebab:n});for(let e of d)await u(`commands/${e.file}`,e.content);let f=wn({pascal:t,kebab:n,plural:r,pluralPascal:i});for(let e of f)await u(`queries/${e.file}`,e.content);let p=Tn({pascal:t,kebab:n});for(let e of p)await u(`events/${e.file}`,e.content);await u(`${n}.repository.ts`,fn({pascal:t,kebab:n,dtoPrefix:`./dtos`,tokenScope:c}));let m={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},h={inmemory:()=>U({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),drizzle:()=>En({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),prisma:()=>On({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`,prismaClientPath:s})},g=m[a]??`${B(a)}-${n}`,_=h[a]??(()=>pn({pascal:t,kebab:n,repoType:a,repoPrefix:`.`,dtoPrefix:`./dtos`}));await u(`${g}.repository.ts`,_()),o||(a!==`inmemory`&&await u(`in-memory-${n}.repository.ts`,U({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`})),await u(`__tests__/${n}.controller.test.ts`,_n({pascal:t,kebab:n,plural:r})),await u(`__tests__/${n}.repository.test.ts`,vn({pascal:t,kebab:n,plural:r,repoPrefix:`../${m.inmemory??`in-memory-${n}`}.repository`})))}async function Mn(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noEntity:o,noTests:s,prismaClientPath:c,tokenScope:l,style:u,write:d}=e;await d(`${n}.module.ts`,tn({pascal:t,kebab:n,plural:r,repo:a,style:u})),await d(`constants.ts`,a===`drizzle`?Dn({pascal:t,kebab:n}):sn({pascal:t,kebab:n})),await d(`presentation/${n}.controller.ts`,an({pascal:t,kebab:n,plural:r,pluralPascal:i})),await d(`application/dtos/create-${n}.dto.ts`,cn({pascal:t,kebab:n})),await d(`application/dtos/update-${n}.dto.ts`,ln({pascal:t,kebab:n})),await d(`application/dtos/${n}-response.dto.ts`,un({pascal:t,kebab:n}));let f=dn({pascal:t,kebab:n,plural:r,pluralPascal:i});for(let e of f)await d(`application/use-cases/${e.file}`,e.content);await d(`domain/repositories/${n}.repository.ts`,fn({pascal:t,kebab:n,tokenScope:l})),await d(`domain/services/${n}-domain.service.ts`,mn({pascal:t,kebab:n}));let p={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},m={inmemory:()=>U({pascal:t,kebab:n}),drizzle:()=>En({pascal:t,kebab:n}),prisma:()=>On({pascal:t,kebab:n,prismaClientPath:c})},h=p[a]??`${B(a)}-${n}`,g=m[a]??(()=>pn({pascal:t,kebab:n,repoType:a}));await d(`infrastructure/repositories/${h}.repository.ts`,g()),o||(await d(`domain/entities/${n}.entity.ts`,hn({pascal:t,kebab:n})),await d(`domain/value-objects/${n}-id.vo.ts`,gn({pascal:t,kebab:n}))),s||(a!==`inmemory`&&await d(`infrastructure/repositories/in-memory-${n}.repository.ts`,U({pascal:t,kebab:n})),await d(`__tests__/${n}.controller.test.ts`,_n({pascal:t,kebab:n,plural:r})),await d(`__tests__/${n}.repository.test.ts`,vn({pascal:t,kebab:n,plural:r})))}function Nn(e){return e?typeof e==`string`?e:e.name:`inmemory`}async function Pn(e){let{name:t,modulesDir:n,noEntity:r,noTests:i,repo:a=`inmemory`,force:o,dryRun:s}=e,c=e.pluralize!==!1,l=e.pattern??`ddd`;e.minimal&&(l=`minimal`);let u=B(t),d=R(t),f=c?V(u):u,p=c?Ft(d):d,m=S(n,f),h=[],g=o??!1,_={kebab:u,pascal:d,plural:f,pluralPascal:p,moduleDir:m,repo:a,noEntity:r??!1,noTests:i??!1,prismaClientPath:e.prismaClientPath??`@prisma/client`,tokenScope:e.tokenScope??`app`,style:e.style??`define`,write:async(e,t)=>{let n=S(m,e);if(s){h.push(n);return}if(!g&&await ze(n)&&!await F({message:`File exists: ${A.dim(e)}. Overwrite?`,initialValue:!1})){I.warn(`Skipped: ${e}`);return}await M(n,t),h.push(n)},files:h};switch(l){case`minimal`:await kn(_);break;case`rest`:await An(_);break;case`cqrs`:await jn(_);break;default:await Mn(_);break}return s||await Fn(n,d,f,u,_.style),h}async function Fn(e,t,n,r,i=`define`){let a=S(e,`index.ts`),o=await ze(a),s=`./${n}/${r}.module`,c=i===`class`?`${t}Module`:`${t}Module()`;if(!o){await M(a,i===`class`?`import type { AppModuleEntry } from '@forinda/kickjs'
2554
2564
  import { ${t}Module } from '${s}'
2555
2565
 
2556
2566
  export const modules: AppModuleEntry[] = [${c}]
2557
- `);return}let l=await E(a,`utf-8`),u=`import { ${t}Module } from '${s}'`;if(!l.includes(`${t}Module`)){let e=l.lastIndexOf(`import `);if(e!==-1){let t=l.indexOf(`
2567
+ `:`import { defineModules } from '@forinda/kickjs'
2568
+ import { ${t}Module } from '${s}'
2569
+
2570
+ export const modules = defineModules().mount(${c})
2571
+ `);return}let l=await D(a,`utf-8`),u=`import { ${t}Module } from '${s}'`,d=H(s);if(!RegExp(`^import\\s*\\{[^}]*\\b${H(t)}Module\\b[^}]*\\}\\s*from\\s*['"]${d}['"]`,`m`).test(l)){let e=l.lastIndexOf(`import `);if(e!==-1){let t=l.indexOf(`
2558
2572
  `,e);l=l.slice(0,t+1)+u+`
2559
2573
  `+l.slice(t+1)}else l=u+`
2560
- `+l;l=l.replace(/(=\s*\[)([\s\S]*?)(])/,(e,t,n,r)=>{let i=n.trim();if(!i)return`${t}${c}${r}`;let a=i.endsWith(`,`)?``:`,`;return`${t}${n.trimEnd()}${a} ${c}${r}`})}await D(a,l,`utf-8`)}async function jn(e){let{name:t,outDir:n}=e,r=B(t),i=R(t),a=[],o=x(n,`${r}.adapter.ts`);return await j(o,`import {
2574
+ `+l}let f=Ln(l);if(f){let e=l.slice(f.rhsStart,f.rhsEnd+1);RegExp(`\\b${H(t)}Module\\b`).test(e)||(l=In(l,c))}else l=In(l,c);await O(a,l,`utf-8`)}function In(e,t){let n=Ln(e);if(!n)return e;if(n.shape===`array`){let r=e.slice(n.rhsStart+1,n.rhsEnd),i=r.trim(),a;if(!i)a=`[${t}]`;else{let e=i.endsWith(`,`)?``:`,`;a=`[${r.trimEnd()}${e} ${t}]`}return e.slice(0,n.rhsStart)+a+e.slice(n.rhsEnd+1)}return`${e.slice(0,n.chainEnd)}\n .mount(${t})${e.slice(n.chainEnd)}`}function Ln(e){let t=/export\s+const\s+modules\b[^=]*=/.exec(e);if(!t)return null;let n=t.index+t[0].length;for(;n<e.length&&/\s/.test(e[n]??``);)n++;if(e[n]===`[`){let t=Bn(e,n);return t===-1?null:{shape:`array`,rhsStart:n,rhsEnd:t}}if(e.slice(n,n+13)===`defineModules`){let t=Rn(e,n);return t===-1?null:{shape:`chain`,rhsStart:n,rhsEnd:t-1,chainEnd:t}}return null}function Rn(e,t=0){let n=/defineModules\s*\(/g;n.lastIndex=t;let r=n.exec(e);if(!r)return-1;let i=r.index+r[0].length-1;if(e[i]!==`(`||(i=Vn(e,i),i===-1))return-1;for(i++;;){let t=i;for(;t<e.length&&/\s/.test(e[t]??``);)t++;if(e[t]!==`.`||e.slice(t,t+6)!==`.mount`)break;for(t+=6;t<e.length&&/\s/.test(e[t]??``);)t++;if(e[t]!==`(`)break;let n=Vn(e,t);if(n===-1)break;i=n+1}return i}function zn(e,t){let n=e.slice(t,t+2);if(n===`//`){for(t+=2;t<e.length&&e[t]!==`
2575
+ `;)t++;return t}if(n===`/*`){for(t+=2;t+1<e.length&&!(e[t]===`*`&&e[t+1]===`/`);)t++;return t+2}return t}function Bn(e,t){if(e[t]!==`[`)return-1;let n=1,r=t+1;for(;r<e.length;){let t=e.slice(r,r+2);if(t===`//`||t===`/*`){r=zn(e,r);continue}let i=e[r]??``;if(i===`'`||i===`"`||i==="`"){let t=i;for(r++;r<e.length&&e[r]!==t;)e[r]===`\\`&&r++,r++;r<e.length&&r++;continue}if(i===`[`)n++;else if(i===`]`&&(n--,n===0))return r;r++}return-1}function Vn(e,t){if(e[t]!==`(`)return-1;let n=1,r=t+1;for(;r<e.length;){let t=e.slice(r,r+2);if(t===`//`||t===`/*`){r=zn(e,r);continue}let i=e[r]??``;if(i===`'`||i===`"`||i==="`"){let t=i;for(r++;r<e.length&&e[r]!==t;)e[r]===`\\`&&r++,r++;r<e.length&&r++;continue}if(i===`(`)n++;else if(i===`)`&&(n--,n===0))return r;r++}return-1}async function Hn(e){let{name:t,outDir:n}=e,r=B(t),i=R(t),a=[],o=S(n,`${r}.adapter.ts`);return await M(o,`import {
2561
2576
  defineAdapter,
2562
2577
  type AdapterContext,
2563
2578
  type AdapterMiddleware,
@@ -2726,7 +2741,7 @@ export const ${i}Adapter = defineAdapter<${i}AdapterConfig>({
2726
2741
  }
2727
2742
  },
2728
2743
  })
2729
- `),a.push(o),a}async function Mn(e){let{name:t,outDir:n}=e,r=B(t),i=R(t),a=[],o=x(n,`${r}.plugin.ts`);return await j(o,`import {
2744
+ `),a.push(o),a}async function Un(e){let{name:t,outDir:n}=e,r=B(t),i=R(t),a=[],o=S(n,`${r}.plugin.ts`);return await M(o,`import {
2730
2745
  definePlugin,
2731
2746
  type AppAdapter,
2732
2747
  type AppModuleEntry,
@@ -2870,7 +2885,7 @@ export const ${i}Plugin = definePlugin<${i}PluginConfig>({
2870
2885
  },
2871
2886
  }),
2872
2887
  })
2873
- `),a.push(o),a}const Nn={controller:`presentation`,service:`domain/services`,dto:`application/dtos`,guard:`presentation/guards`,middleware:`middleware`},Pn={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`},Fn={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`,command:`commands`,query:`queries`,event:`events`};function U(e){let{type:t,outDir:n,moduleName:r,modulesDir:i=`src/modules`,defaultDir:a,pattern:o=`ddd`,shouldPluralize:s=!0}=e;if(n)return C(n);if(r){let e=o===`ddd`?Nn:o===`cqrs`?Fn:Pn,n=B(r),a=s?V(n):n,c=e[t]??``,l=x(i,a);return C(c?x(l,c):l)}return C(a)}async function In(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=U({type:`middleware`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/middleware`,pattern:i,shouldPluralize:e.pluralize??!0}),o=B(t),s=z(t),c=[],l=x(a,`${o}.middleware.ts`);return await j(l,`import type { Request, Response, NextFunction } from 'express'
2888
+ `),a.push(o),a}const Wn={controller:`presentation`,service:`domain/services`,dto:`application/dtos`,guard:`presentation/guards`,middleware:`middleware`},Gn={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`},Kn={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`,command:`commands`,query:`queries`,event:`events`};function W(e){let{type:t,outDir:n,moduleName:r,modulesDir:i=`src/modules`,defaultDir:a,pattern:o=`ddd`,shouldPluralize:s=!0}=e;if(n)return w(n);if(r){let e=o===`ddd`?Wn:o===`cqrs`?Kn:Gn,n=B(r),a=s?V(n):n,c=e[t]??``,l=S(i,a);return w(c?S(l,c):l)}return w(a)}async function qn(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=W({type:`middleware`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/middleware`,pattern:i,shouldPluralize:e.pluralize??!0}),o=B(t),s=z(t),c=[],l=S(a,`${o}.middleware.ts`);return await M(l,`import type { Request, Response, NextFunction } from 'express'
2874
2889
 
2875
2890
  export interface ${R(t)}Options {
2876
2891
  // Add configuration options here
@@ -2894,7 +2909,7 @@ export function ${s}(options: ${R(t)}Options = {}) {
2894
2909
  next()
2895
2910
  }
2896
2911
  }
2897
- `),c.push(l),c}async function Ln(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=U({type:`guard`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/guards`,pattern:i,shouldPluralize:e.pluralize??!0}),o=B(t),s=z(t),c=R(t),l=[],u=x(a,`${o}.guard.ts`);return await j(u,`import { Container, HttpException } from '@forinda/kickjs'
2912
+ `),c.push(l),c}async function Jn(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=W({type:`guard`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/guards`,pattern:i,shouldPluralize:e.pluralize??!0}),o=B(t),s=z(t),c=R(t),l=[],u=S(a,`${o}.guard.ts`);return await M(u,`import { Container, HttpException } from '@forinda/kickjs'
2898
2913
  import type { RequestContext } from '@forinda/kickjs'
2899
2914
 
2900
2915
  /**
@@ -2930,7 +2945,7 @@ export async function ${s}Guard(ctx: RequestContext, next: () => void): Promise<
2930
2945
  ctx.res.status(401).json({ message: 'Invalid or expired token' })
2931
2946
  }
2932
2947
  }
2933
- `),l.push(u),l}async function Rn(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=U({type:`service`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/services`,pattern:i,shouldPluralize:e.pluralize??!0}),o=B(t),s=R(t),c=[],l=x(a,`${o}.service.ts`);return await j(l,`import { Service } from '@forinda/kickjs'
2948
+ `),l.push(u),l}async function Yn(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=W({type:`service`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/services`,pattern:i,shouldPluralize:e.pluralize??!0}),o=B(t),s=R(t),c=[],l=S(a,`${o}.service.ts`);return await M(l,`import { Service } from '@forinda/kickjs'
2934
2949
 
2935
2950
  @Service()
2936
2951
  export class ${s}Service {
@@ -2939,7 +2954,7 @@ export class ${s}Service {
2939
2954
  // @Inject(MY_REPO) private readonly repo: IMyRepository,
2940
2955
  // ) {}
2941
2956
  }
2942
- `),c.push(l),c}async function zn(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=U({type:`controller`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/controllers`,pattern:i,shouldPluralize:e.pluralize??!0}),o=B(t),s=R(t),c=[],l=x(a,`${o}.controller.ts`);return await j(l,`import { Controller, Get, Post, type Ctx } from '@forinda/kickjs'
2957
+ `),c.push(l),c}async function Xn(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=W({type:`controller`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/controllers`,pattern:i,shouldPluralize:e.pluralize??!0}),o=B(t),s=R(t),c=[],l=S(a,`${o}.controller.ts`);return await M(l,`import { Controller, Get, Post, type Ctx } from '@forinda/kickjs'
2943
2958
 
2944
2959
  // \`Ctx<KickRoutes.${s}Controller['<method>']>\` is generated by
2945
2960
  // \`kick typegen\` (auto-run on \`kick dev\`). After the first run, your IDE
@@ -2960,7 +2975,7 @@ export class ${s}Controller {
2960
2975
  ctx.created({ message: '${s} created', data: ctx.body })
2961
2976
  }
2962
2977
  }
2963
- `),c.push(l),c}async function Bn(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=U({type:`dto`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/dtos`,pattern:i,shouldPluralize:e.pluralize??!0}),o=B(t),s=R(t),c=z(t),l=[],u=x(a,`${o}.dto.ts`);return await j(u,`import { z } from 'zod'
2978
+ `),c.push(l),c}async function Zn(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=W({type:`dto`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/dtos`,pattern:i,shouldPluralize:e.pluralize??!0}),o=B(t),s=R(t),c=z(t),l=[],u=S(a,`${o}.dto.ts`);return await M(u,`import { z } from 'zod'
2964
2979
 
2965
2980
  export const ${c}Schema = z.object({
2966
2981
  // Define your schema fields here
@@ -2968,8 +2983,8 @@ export const ${c}Schema = z.object({
2968
2983
  })
2969
2984
 
2970
2985
  export type ${s}DTO = z.infer<typeof ${c}Schema>
2971
- `),l.push(u),l}async function Vn(e){let t=x(e.outDir,`kick.config.ts`),n=e.modulesDir??`src/modules`,r=e.defaultRepo??`inmemory`;return h(t)&&!e.force&&!await F({message:`kick.config.ts already exists. Overwrite?`,initialValue:!1})?(console.log(`
2972
- Skipped — existing kick.config.ts preserved.`),[]):(await j(t,`import { defineConfig } from '@forinda/kickjs-cli'
2986
+ `),l.push(u),l}async function Qn(e){let t=S(e.outDir,`kick.config.ts`),n=e.modulesDir??`src/modules`,r=e.defaultRepo??`inmemory`;return g(t)&&!e.force&&!await F({message:`kick.config.ts already exists. Overwrite?`,initialValue:!1})?(console.log(`
2987
+ Skipped — existing kick.config.ts preserved.`),[]):(await M(t,`import { defineConfig } from '@forinda/kickjs-cli'
2973
2988
 
2974
2989
  export default defineConfig({
2975
2990
  modules: {
@@ -3006,18 +3021,18 @@ export default defineConfig({
3006
3021
  },
3007
3022
  ],
3008
3023
  })
3009
- `),[t])}const Hn=new Set([`rest`,`ddd`,`cqrs`,`minimal`]);function Un(e,t){if(t)return t;try{let t=JSON.parse(_(x(e,`package.json`),`utf-8`));if(t.name)return t.name.replace(/^@[^/]+\//,``)}catch{}return e.split(`/`).findLast(Boolean)??`app`}function Wn(e,t){if(t)return t;try{let t=JSON.parse(_(x(e,`package.json`),`utf-8`));if(t.packageManager)return t.packageManager.split(`@`)[0]}catch{}return`pnpm`}async function Gn(e,t){if(t)return t;try{let t=(await r(e))?.pattern;if(t&&Hn.has(t))return t}catch{}return`ddd`}async function Kn(e){let t=e.only??`all`,n=Un(e.outDir,e.name),r=Wn(e.outDir,e.pm),i=await Gn(e.outDir,e.template),a=t===`agents`||t===`both`||t===`all`,o=t===`claude`||t===`both`||t===`all`,s=t===`skills`||t===`all`,c=[];a&&c.push({file:x(e.outDir,`AGENTS.md`),render:()=>at(n,i,r)}),o&&c.push({file:x(e.outDir,`CLAUDE.md`),render:()=>it(n,i,r)}),s&&c.push({file:x(e.outDir,`kickjs-skills.md`),render:()=>ot(n,i,r)});let l=[];for(let{file:t,render:n}of c){if(h(t)&&!e.force&&!await F({message:`${t.replace(e.outDir+`/`,``)} already exists. Overwrite?`,initialValue:!1})){console.log(` Skipped — existing ${t.replace(e.outDir+`/`,``)} preserved.`);continue}await j(t,n()),l.push(t)}return l}function qn(e,t){if(e[t]!==`{`)return-1;let n=1;for(let r=t+1;r<e.length;r++){let t=e[r];if(t===`{`)n++;else if(t===`}`&&(n--,n===0))return r}return-1}function W(e,t){let n=t.exec(e);if(!n)return null;let r=n.index+n[0].length-1,i=qn(e,r);return i===-1?null:e.slice(r+1,i)}function G(e,t,n){let r=` `.repeat(n);return e.split(`
3024
+ `),[t])}const $n=new Set([`rest`,`ddd`,`cqrs`,`minimal`]);function er(e,t){if(t)return t;try{let t=JSON.parse(v(S(e,`package.json`),`utf-8`));if(t.name)return t.name.replace(/^@[^/]+\//,``)}catch{}return e.split(`/`).findLast(Boolean)??`app`}function tr(e,t){if(t)return t;try{let t=JSON.parse(v(S(e,`package.json`),`utf-8`));if(t.packageManager)return t.packageManager.split(`@`)[0]}catch{}return`pnpm`}async function nr(e,t){if(t)return t;try{let t=(await r(e))?.pattern;if(t&&$n.has(t))return t}catch{}return`ddd`}async function rr(e){let t=e.only??`all`,n=er(e.outDir,e.name),r=tr(e.outDir,e.pm),i=await nr(e.outDir,e.template),a=t===`agents`||t===`both`||t===`all`,o=t===`claude`||t===`both`||t===`all`,s=t===`skills`||t===`all`,c=[];a&&c.push({file:S(e.outDir,`AGENTS.md`),render:()=>st(n,i,r)}),o&&c.push({file:S(e.outDir,`CLAUDE.md`),render:()=>ot(n,i,r)}),s&&c.push({file:S(e.outDir,`kickjs-skills.md`),render:()=>ct(n,i,r)});let l=[];for(let{file:t,render:n}of c){if(g(t)&&!e.force&&!await F({message:`${t.replace(e.outDir+`/`,``)} already exists. Overwrite?`,initialValue:!1})){console.log(` Skipped — existing ${t.replace(e.outDir+`/`,``)} preserved.`);continue}await M(t,n()),l.push(t)}return l}function ir(e,t){if(e[t]!==`{`)return-1;let n=1;for(let r=t+1;r<e.length;r++){let t=e[r];if(t===`{`)n++;else if(t===`}`&&(n--,n===0))return r}return-1}function G(e,t){let n=t.exec(e);if(!n)return null;let r=n.index+n[0].length-1,i=ir(e,r);return i===-1?null:e.slice(r+1,i)}function K(e,t,n){let r=` `.repeat(n);return e.split(`
3010
3025
  `).map(e=>{if(e.trim()===``)return e;let n=RegExp(`^ {0,${t}}`);return r+e.replace(n,``)}).join(`
3011
- `)}function Jn(e){return e.replaceAll(/import\s*\{\s*([^}]+)\s*\}\s*from\s*'@forinda\/kickjs'/g,(e,t)=>{let n=t.split(`,`).map(e=>e.trim()).filter(e=>e&&e!==`Container`&&e!==`type Container`&&e!==`type AppModule`&&e!==`AppModule`&&e!==`type ModuleRoutes`&&e!==`ModuleRoutes`);return n.includes(`defineModule`)||n.push(`defineModule`),`import { ${n.join(`, `)} } from '@forinda/kickjs'`})}function Yn(e,t){return e.replaceAll(/import\s*\{\s*([^}]+)\s*\}\s*from\s*'@forinda\/kickjs'/g,(e,n)=>{let r=n.split(`,`).map(e=>e.trim()).filter(e=>e&&e!==`defineModule`);return t.container&&!r.includes(`Container`)&&r.push(`Container`),t.appModule&&!r.some(e=>e===`AppModule`||e===`type AppModule`)&&r.push(`type AppModule`),t.moduleRoutes&&!r.some(e=>e===`ModuleRoutes`||e===`type ModuleRoutes`)&&r.push(`type ModuleRoutes`),t.contributorRegistrations&&!r.some(e=>e===`ContributorRegistrations`||e===`type ContributorRegistrations`)&&r.push(`type ContributorRegistrations`),`import { ${r.join(`, `)} } from '@forinda/kickjs'`})}function Xn(e){if(/\bdefineModule\s*\(/.test(e))return{migrated:null,reason:`already in target form`};let t=[...e.matchAll(/export\s+class\s+(\w+Module)\s+implements\s+AppModule\s*\{/g)];if(t.length===0)return{migrated:null,reason:`no class form detected`};if(t.length>1)return{migrated:null,reason:`multiple module classes in one file — migrate manually`};let n=t[0],r=n[1],i=n.index+n[0].length-1,a=qn(e,i);if(a===-1)return{migrated:null,reason:`unbalanced class braces`};let o=e.slice(i+1,a),s=e.slice(0,n.index),c=e.slice(a+1),l=W(o,/register\s*\(([^)]*)\)\s*:\s*void\s*\{/),u=W(o,/contributors\s*\(\s*\)\s*:\s*ContributorRegistrations\s*\{/),d=W(o,/routes\s*\(\s*\)\s*:\s*[A-Za-z|[\]\s]+\{/);if(!d)return{migrated:null,reason:`routes() method missing or signature unrecognized`};let f=Jn(s),p=``;return l&&(p+=` register(container) {${G(l,4,6)} },\n\n`),u&&(p+=` contributors() {${G(u,4,6)} },\n\n`),p+=` routes() {${G(d,4,6)} },`,{migrated:`${f}${`export const ${r} = defineModule({
3026
+ `)}function ar(e){return e.replaceAll(/import\s*\{\s*([^}]+)\s*\}\s*from\s*'@forinda\/kickjs'/g,(e,t)=>{let n=t.split(`,`).map(e=>e.trim()).filter(e=>e&&e!==`Container`&&e!==`type Container`&&e!==`type AppModule`&&e!==`AppModule`&&e!==`type ModuleRoutes`&&e!==`ModuleRoutes`);return n.includes(`defineModule`)||n.push(`defineModule`),`import { ${n.join(`, `)} } from '@forinda/kickjs'`})}function or(e,t){return e.replaceAll(/import\s*\{\s*([^}]+)\s*\}\s*from\s*'@forinda\/kickjs'/g,(e,n)=>{let r=n.split(`,`).map(e=>e.trim()).filter(e=>e&&e!==`defineModule`);return t.container&&!r.includes(`Container`)&&r.push(`Container`),t.appModule&&!r.some(e=>e===`AppModule`||e===`type AppModule`)&&r.push(`type AppModule`),t.moduleRoutes&&!r.some(e=>e===`ModuleRoutes`||e===`type ModuleRoutes`)&&r.push(`type ModuleRoutes`),t.contributorRegistrations&&!r.some(e=>e===`ContributorRegistrations`||e===`type ContributorRegistrations`)&&r.push(`type ContributorRegistrations`),`import { ${r.join(`, `)} } from '@forinda/kickjs'`})}function sr(e){if(/\bdefineModule\s*\(/.test(e))return{migrated:null,reason:`already in target form`};let t=[...e.matchAll(/export\s+class\s+(\w+Module)\s+implements\s+AppModule\s*\{/g)];if(t.length===0)return{migrated:null,reason:`no class form detected`};if(t.length>1)return{migrated:null,reason:`multiple module classes in one file — migrate manually`};let n=t[0],r=n[1],i=n.index+n[0].length-1,a=ir(e,i);if(a===-1)return{migrated:null,reason:`unbalanced class braces`};let o=e.slice(i+1,a),s=e.slice(0,n.index),c=e.slice(a+1),l=G(o,/register\s*\(([^)]*)\)\s*:\s*void\s*\{/),u=G(o,/contributors\s*\(\s*\)\s*:\s*ContributorRegistrations\s*\{/),d=G(o,/routes\s*\(\s*\)\s*:\s*[A-Za-z|[\]\s]+\{/);if(!d)return{migrated:null,reason:`routes() method missing or signature unrecognized`};let f=ar(s),p=``;return l&&(p+=` register(container) {${K(l,4,6)} },\n\n`),u&&(p+=` contributors() {${K(u,4,6)} },\n\n`),p+=` routes() {${K(d,4,6)} },`,{migrated:`${f}${`export const ${r} = defineModule({
3012
3027
  name: '${r}',
3013
3028
  build: () => ({
3014
3029
  ${p}
3015
3030
  }),
3016
- })`}${c}`}}function Zn(e){if(/export\s+class\s+\w+Module\s+implements\s+AppModule\s*\{/.test(e))return{migrated:null,reason:`already in target form`};let t=[...e.matchAll(/export\s+const\s+(\w+Module)\s*=\s*defineModule\s*\(\s*\{/g)];if(t.length===0)return{migrated:null,reason:`no defineModule form detected`};if(t.length>1)return{migrated:null,reason:`multiple defineModule blocks in one file — migrate manually`};let n=t[0],r=n[1],i=n.index+n[0].length-1,a=qn(e,i);if(a===-1)return{migrated:null,reason:`unbalanced defineModule braces`};let o=e.indexOf(`)`,a);if(o===-1)return{migrated:null,reason:`unbalanced defineModule call parens`};let s=e.slice(i+1,a),c=e.slice(0,n.index),l=o+1;for(;l<e.length&&(e[l]===`
3017
- `||e[l]===`\r`);)l++;let u=e.slice(l),d=/build\s*:\s*\([^)]*\)\s*=>\s*\(\s*\{/g.exec(s);if(!d)return{migrated:null,reason:`build: () => ({...}) not found in defineModule`};let f=d.index+d[0].length-1,p=qn(s,f);if(p===-1)return{migrated:null,reason:`unbalanced build() braces`};let m=s.slice(f+1,p),h=W(m,/register\s*\(([^)]*)\)\s*\{/),g=W(m,/contributors\s*\(\s*\)\s*\{/),_=W(m,/routes\s*\(\s*\)\s*\{/);if(!_)return{migrated:null,reason:`routes() method missing inside build()`};let ee=Yn(c,{container:h!==null,appModule:!0,moduleRoutes:!0,contributorRegistrations:g!==null}),v=``;return h!==null&&(v+=` register(container: Container): void {${G(h,6,4)} }\n\n`),g!==null&&(v+=` contributors(): ContributorRegistrations {${G(g,6,4)} }\n\n`),v+=` routes(): ModuleRoutes {${G(_,6,4)} }`,{migrated:`${ee}${`export class ${r} implements AppModule {
3018
- ${v}
3031
+ })`}${c}`}}function cr(e){if(/export\s+class\s+\w+Module\s+implements\s+AppModule\s*\{/.test(e))return{migrated:null,reason:`already in target form`};let t=[...e.matchAll(/export\s+const\s+(\w+Module)\s*=\s*defineModule\s*\(\s*\{/g)];if(t.length===0)return{migrated:null,reason:`no defineModule form detected`};if(t.length>1)return{migrated:null,reason:`multiple defineModule blocks in one file — migrate manually`};let n=t[0],r=n[1],i=n.index+n[0].length-1,a=ir(e,i);if(a===-1)return{migrated:null,reason:`unbalanced defineModule braces`};let o=e.indexOf(`)`,a);if(o===-1)return{migrated:null,reason:`unbalanced defineModule call parens`};let s=e.slice(i+1,a),c=e.slice(0,n.index),l=o+1;for(;l<e.length&&(e[l]===`
3032
+ `||e[l]===`\r`);)l++;let u=e.slice(l),d=/build\s*:\s*\([^)]*\)\s*=>\s*\(\s*\{/g.exec(s);if(!d)return{migrated:null,reason:`build: () => ({...}) not found in defineModule`};let f=d.index+d[0].length-1,p=ir(s,f);if(p===-1)return{migrated:null,reason:`unbalanced build() braces`};let m=s.slice(f+1,p),h=G(m,/register\s*\(([^)]*)\)\s*\{/),g=G(m,/contributors\s*\(\s*\)\s*\{/),_=G(m,/routes\s*\(\s*\)\s*\{/);if(!_)return{migrated:null,reason:`routes() method missing inside build()`};let v=or(c,{container:h!==null,appModule:!0,moduleRoutes:!0,contributorRegistrations:g!==null}),y=``;return h!==null&&(y+=` register(container: Container): void {${K(h,6,4)} }\n\n`),g!==null&&(y+=` contributors(): ContributorRegistrations {${K(g,6,4)} }\n\n`),y+=` routes(): ModuleRoutes {${K(_,6,4)} }`,{migrated:`${v}${`export class ${r} implements AppModule {
3033
+ ${y}
3019
3034
  }
3020
- `}${u}`}}function Qn(e,t){return t===`class`?Zn(e):Xn(e)}function $n(e,t){let n=e,r=!1;if(t===`define`){/\bAppModuleClass\b/.test(n)&&(n=n.replaceAll(/\bAppModuleClass\b/g,`AppModuleEntry`),r=!0);let e=/(=\s*\[)([\s\S]*?)(])/,t=e.exec(n);if(t){let i=t[1],a=t[3],o=t[2],s=o.replaceAll(/(\b\w+Module)(?![(.])/g,`$1()`);s!==o&&(n=n.replace(e,`${i}${s}${a}`),r=!0)}}else{/\bAppModuleEntry\b/.test(n)&&(n=n.replaceAll(/\bAppModuleEntry\b/g,`AppModuleClass`),r=!0);let e=/(=\s*\[)([\s\S]*?)(])/,t=e.exec(n);if(t){let i=t[1],a=t[3],o=t[2],s=o.replaceAll(/(\b\w+Module)\s*\(\s*\)/g,`$1`);s!==o&&(n=n.replace(e,`${i}${s}${a}`),r=!0)}}return r?{migrated:n}:{migrated:null,reason:`no changes needed`}}async function er(e){let t=[];return await n(C(e),0),t;async function n(e,r){let i;try{i=await me(e)}catch{return}for(let a of i){if(a===`node_modules`||a===`dist`||a===`.kickjs`)continue;let i=x(e,a),o;try{o=await ge(i)}catch{continue}o.isDirectory()?await n(i,r+1):(a.endsWith(`.module.ts`)||a===`index.ts`&&r===1)&&t.push(i)}}}async function tr(e,t){let n=0;return await r(e,t),n;async function r(e,t){let i;try{i=await me(e)}catch{return}await pe(t,{recursive:!0});for(let a of i){if(a===`node_modules`||a===`dist`||a===`.kickjs`)continue;let i=x(e,a),o=x(t,a),s;try{s=await ge(i)}catch{continue}s.isDirectory()?await r(i,o):(await fe(i,o),n++)}}}function nr(e){return x(e,`.kickjs`,`codemod-backups`,`${new Date().toISOString().replaceAll(/[:.]/g,`-`)}-modules`)}async function rr(e,t){let{dryRun:n=!1,cwd:r=process.cwd(),target:i}=t,a=t.backup??!n,o=await er(e),s=await E(x(e,`index.ts`),`utf-8`).then(()=>!0,()=>!1),c=null;a&&(o.length>0||s)&&(c=nr(r),await tr(e,c));let l=[];for(let e of o){let t=Qn(await E(e,`utf-8`),i);if(t.migrated==null){l.push({path:e,status:`skipped`,reason:t.reason});continue}n||await D(e,t.migrated,`utf-8`),l.push({path:e,status:`migrated`})}let u=x(e,`index.ts`),d=null;try{d=await E(u,`utf-8`)}catch{return{target:i,files:l,indexStatus:`not-found`,indexPath:u,backupDir:c}}let f=$n(d,i);return f.migrated==null?{target:i,files:l,indexStatus:`skipped`,indexPath:u,indexReason:f.reason,backupDir:c}:(n||await D(u,f.migrated,`utf-8`),{target:i,files:l,indexStatus:`migrated`,indexPath:u,backupDir:c})}async function ir(e,t){let n=await er(e),r=[],i=t===`define`?/export\s+class\s+\w+Module\s+implements\s+AppModule\s*\{/:/export\s+const\s+\w+Module\s*=\s*defineModule\s*\(/;for(let e of n){let t=await E(e,`utf-8`);i.test(t)&&r.push(e)}return r}async function ar(e={}){let t=e.strategy??`jwt`,n=e.outDir??`src/modules/auth`,r=x(n,`dto`),i=[],a=x(n,`auth.module.ts`);await j(a,`import { Module } from '@forinda/kickjs'
3035
+ `}${u}`}}function lr(e,t){return t===`class`?cr(e):sr(e)}function ur(e,t){let n=e,r=!1;if(t===`define`){/\bAppModuleClass\b/.test(n)&&(n=n.replaceAll(/\bAppModuleClass\b/g,`AppModuleEntry`),r=!0);let e=/(=\s*\[)([\s\S]*?)(])/,t=e.exec(n);if(t){let i=t[1],a=t[3],o=t[2],s=o.replaceAll(/(\b\w+Module)(?![(.])/g,`$1()`);s!==o&&(n=n.replace(e,`${i}${s}${a}`),r=!0)}}else{/\bAppModuleEntry\b/.test(n)&&(n=n.replaceAll(/\bAppModuleEntry\b/g,`AppModuleClass`),r=!0);let e=/(=\s*\[)([\s\S]*?)(])/,t=e.exec(n);if(t){let i=t[1],a=t[3],o=t[2],s=o.replaceAll(/(\b\w+Module)\s*\(\s*\)/g,`$1`);s!==o&&(n=n.replace(e,`${i}${s}${a}`),r=!0)}}return r?{migrated:n}:{migrated:null,reason:`no changes needed`}}async function dr(e){let t=[];return await n(w(e),0),t;async function n(e,r){let i;try{i=await he(e)}catch{return}for(let a of i){if(a===`node_modules`||a===`dist`||a===`.kickjs`)continue;let i=S(e,a),o;try{o=await _e(i)}catch{continue}o.isDirectory()?await n(i,r+1):(a.endsWith(`.module.ts`)||a===`index.ts`&&r===1)&&t.push(i)}}}async function fr(e,t){let n=0;return await r(e,t),n;async function r(e,t){let i;try{i=await he(e)}catch{return}await me(t,{recursive:!0});for(let a of i){if(a===`node_modules`||a===`dist`||a===`.kickjs`)continue;let i=S(e,a),o=S(t,a),s;try{s=await _e(i)}catch{continue}s.isDirectory()?await r(i,o):(await pe(i,o),n++)}}}function pr(e){return S(e,`.kickjs`,`codemod-backups`,`${new Date().toISOString().replaceAll(/[:.]/g,`-`)}-modules`)}async function mr(e,t){let{dryRun:n=!1,cwd:r=process.cwd(),target:i}=t,a=t.backup??!n,o=await dr(e),s=await D(S(e,`index.ts`),`utf-8`).then(()=>!0,()=>!1),c=null;a&&(o.length>0||s)&&(c=pr(r),await fr(e,c));let l=[];for(let e of o){let t=lr(await D(e,`utf-8`),i);if(t.migrated==null){l.push({path:e,status:`skipped`,reason:t.reason});continue}n||await O(e,t.migrated,`utf-8`),l.push({path:e,status:`migrated`})}let u=S(e,`index.ts`),d=null;try{d=await D(u,`utf-8`)}catch{return{target:i,files:l,indexStatus:`not-found`,indexPath:u,backupDir:c}}let f=ur(d,i);return f.migrated==null?{target:i,files:l,indexStatus:`skipped`,indexPath:u,indexReason:f.reason,backupDir:c}:(n||await O(u,f.migrated,`utf-8`),{target:i,files:l,indexStatus:`migrated`,indexPath:u,backupDir:c})}async function hr(e,t){let n=await dr(e),r=[],i=t===`define`?/export\s+class\s+\w+Module\s+implements\s+AppModule\s*\{/:/export\s+const\s+\w+Module\s*=\s*defineModule\s*\(/;for(let e of n){let t=await D(e,`utf-8`);i.test(t)&&r.push(e)}return r}async function gr(e={}){let t=e.strategy??`jwt`,n=e.outDir??`src/modules/auth`,r=S(n,`dto`),i=[],a=S(n,`auth.module.ts`);await M(a,`import { Module } from '@forinda/kickjs'
3021
3036
  import { AuthController } from './auth.controller'
3022
3037
  import { AuthService } from './auth.service'
3023
3038
 
@@ -3026,7 +3041,7 @@ import { AuthService } from './auth.service'
3026
3041
  services: [AuthService],
3027
3042
  })
3028
3043
  export class AuthModule {}
3029
- `),i.push(a);let o=x(n,`auth.controller.ts`);await j(o,t===`jwt`?or():cr()),i.push(o);let s=x(n,`auth.service.ts`);await j(s,t===`jwt`?sr():lr()),i.push(s);let c=x(r,`register.dto.ts`);await j(c,`import { z } from 'zod'
3044
+ `),i.push(a);let o=S(n,`auth.controller.ts`);await M(o,t===`jwt`?_r():yr()),i.push(o);let s=S(n,`auth.service.ts`);await M(s,t===`jwt`?vr():br()),i.push(s);let c=S(r,`register.dto.ts`);await M(c,`import { z } from 'zod'
3030
3045
 
3031
3046
  export const RegisterDto = z.object({
3032
3047
  email: z.string().email(),
@@ -3035,7 +3050,7 @@ export const RegisterDto = z.object({
3035
3050
  })
3036
3051
 
3037
3052
  export type RegisterInput = z.infer<typeof RegisterDto>
3038
- `),i.push(c);let l=x(r,`login.dto.ts`);await j(l,`import { z } from 'zod'
3053
+ `),i.push(c);let l=S(r,`login.dto.ts`);await M(l,`import { z } from 'zod'
3039
3054
 
3040
3055
  export const LoginDto = z.object({
3041
3056
  email: z.string().email(),
@@ -3043,7 +3058,7 @@ export const LoginDto = z.object({
3043
3058
  })
3044
3059
 
3045
3060
  export type LoginInput = z.infer<typeof LoginDto>
3046
- `),i.push(l);let u=x(n,`auth.test.ts`);if(await j(u,`import { describe, it, expect } from 'vitest'
3061
+ `),i.push(l);let u=S(n,`auth.test.ts`);if(await M(u,`import { describe, it, expect } from 'vitest'
3047
3062
 
3048
3063
  describe('Auth Module', () => {
3049
3064
  it.todo('POST /register — creates a new user')
@@ -3052,7 +3067,7 @@ describe('Auth Module', () => {
3052
3067
  it.todo('POST /logout — invalidates session/token')
3053
3068
  it.todo('GET /me — returns authenticated user')
3054
3069
  })
3055
- `),i.push(u),e.roleGuards!==!1){let e=x(n,`auth.guard.ts`);await j(e,`import { Roles } from '@forinda/kickjs-auth'
3070
+ `),i.push(u),e.roleGuards!==!1){let e=S(n,`auth.guard.ts`);await M(e,`import { Roles } from '@forinda/kickjs-auth'
3056
3071
 
3057
3072
  /**
3058
3073
  * Role-based access guard.
@@ -3063,7 +3078,7 @@ describe('Auth Module', () => {
3063
3078
  */
3064
3079
  export const AdminOnly = Roles('admin')
3065
3080
  export const ManagerOnly = Roles('manager')
3066
- `),i.push(e)}return i}function or(){return`import { Controller, Post, Get } from '@forinda/kickjs'
3081
+ `),i.push(e)}return i}function _r(){return`import { Controller, Post, Get } from '@forinda/kickjs'
3067
3082
  import { Authenticated, Public } from '@forinda/kickjs-auth'
3068
3083
  import type { RequestContext } from '@forinda/kickjs'
3069
3084
  import { Autowired } from '@forinda/kickjs'
@@ -3099,7 +3114,7 @@ export class AuthController {
3099
3114
  return ctx.json({ user: ctx.user })
3100
3115
  }
3101
3116
  }
3102
- `}function sr(){return`import { Service, Autowired } from '@forinda/kickjs'
3117
+ `}function vr(){return`import { Service, Autowired } from '@forinda/kickjs'
3103
3118
  import { PasswordService } from '@forinda/kickjs-auth'
3104
3119
  import type { RegisterInput } from './dto/register.dto'
3105
3120
  import type { LoginInput } from './dto/login.dto'
@@ -3138,7 +3153,7 @@ export class AuthService {
3138
3153
  return { user: { id: user.id, email: user.email, name: user.name } }
3139
3154
  }
3140
3155
  }
3141
- `}function cr(){return`import { Controller, Post, Get } from '@forinda/kickjs'
3156
+ `}function yr(){return`import { Controller, Post, Get } from '@forinda/kickjs'
3142
3157
  import { Authenticated, Public } from '@forinda/kickjs-auth'
3143
3158
  import { sessionLogin, sessionLogout } from '@forinda/kickjs-auth'
3144
3159
  import type { RequestContext } from '@forinda/kickjs'
@@ -3177,7 +3192,7 @@ export class AuthController {
3177
3192
  return ctx.json({ user: ctx.user })
3178
3193
  }
3179
3194
  }
3180
- `}function lr(){return`import { Service, Autowired } from '@forinda/kickjs'
3195
+ `}function br(){return`import { Service, Autowired } from '@forinda/kickjs'
3181
3196
  import { PasswordService } from '@forinda/kickjs-auth'
3182
3197
  import type { RegisterInput } from './dto/register.dto'
3183
3198
  import type { LoginInput } from './dto/login.dto'
@@ -3214,7 +3229,7 @@ export class AuthService {
3214
3229
  return { id: user.id, email: user.email, name: user.name }
3215
3230
  }
3216
3231
  }
3217
- `}async function ur(e){let{name:t,outDir:n}=e,r=R(t),i=B(t),a=z(t),o=e.queue??`${i}-queue`,s=[];return await(async(e,t)=>{let r=x(n,e);await j(r,t),s.push(r)})(`${i}.job.ts`,`import { Inject } from '@forinda/kickjs'
3232
+ `}async function xr(e){let{name:t,outDir:n}=e,r=R(t),i=B(t),a=z(t),o=e.queue??`${i}-queue`,s=[];return await(async(e,t)=>{let r=S(n,e);await M(r,t),s.push(r)})(`${i}.job.ts`,`import { Inject } from '@forinda/kickjs'
3218
3233
  import { Job, Process, QUEUE_MANAGER, type QueueService } from '@forinda/kickjs-queue'
3219
3234
 
3220
3235
  /**
@@ -3247,7 +3262,7 @@ export class ${r}Job {
3247
3262
  // Handle high-priority variant of this job
3248
3263
  }
3249
3264
  }
3250
- `),s}const dr={string:{ts:`string`,zod:`z.string()`},text:{ts:`string`,zod:`z.string()`},number:{ts:`number`,zod:`z.number()`},int:{ts:`number`,zod:`z.number().int()`},float:{ts:`number`,zod:`z.number()`},boolean:{ts:`boolean`,zod:`z.boolean()`},date:{ts:`string`,zod:`z.string().datetime()`},email:{ts:`string`,zod:`z.string().email()`},url:{ts:`string`,zod:`z.string().url()`},uuid:{ts:`string`,zod:`z.string().uuid()`},json:{ts:`any`,zod:`z.any()`}};function fr(e){return e.map(e=>{let t=e.indexOf(`:`);if(t===-1)throw Error(`Invalid field: "${e}". Use format: name:type (e.g. title:string)`);let n=e.slice(0,t),r=e.slice(t+1);if(!n||!r)throw Error(`Invalid field: "${e}". Use format: name:type (e.g. title:string)`);let i=!1;r.endsWith(`:optional`)&&(r=r.slice(0,-9),i=!0),n.endsWith(`?`)&&(n=n.slice(0,-1),i=!0),r.endsWith(`?`)&&(r=r.slice(0,-1),i=!0);let a=r;if(a.startsWith(`enum:`)){let e=a.slice(5).split(`,`);return{name:n,type:`enum`,tsType:e.map(e=>`'${e}'`).join(` | `),zodType:`z.enum([${e.map(e=>`'${e}'`).join(`, `)}])`,optional:i}}let o=dr[a];if(!o){let e=[...Object.keys(dr),`enum:a,b,c`].join(`, `);throw Error(`Unknown field type: "${a}". Valid types: ${e}`)}return{name:n,type:a,tsType:o.ts,zodType:o.zod,optional:i}})}async function pr(e){let{name:t,fields:n,modulesDir:r,noEntity:i,noTests:a,repo:o=`inmemory`,tokenScope:s=`app`,style:c=`define`}=e,l=e.pluralize!==!1,u=B(t),d=R(t);z(t);let f=l?V(u):u,p=l?At(d):d,m=x(r,f),h=[],g=async(e,t)=>{let n=x(m,e);await j(n,t),h.push(n)};await g(`${u}.module.ts`,xr(d,u,f,c)),await g(`constants.ts`,_r(d,n)),await g(`presentation/${u}.controller.ts`,Sr(d,u,f,p)),await g(`application/dtos/create-${u}.dto.ts`,mr(d,n)),await g(`application/dtos/update-${u}.dto.ts`,hr(d,n)),await g(`application/dtos/${u}-response.dto.ts`,gr(d,n));let _=Tr(d,u,f,p);for(let e of _)await g(`application/use-cases/${e.file}`,e.content);return await g(`domain/repositories/${u}.repository.ts`,Cr(d,u,s)),await g(`domain/services/${u}-domain.service.ts`,wr(d,u)),o===`inmemory`&&await g(`infrastructure/repositories/in-memory-${u}.repository.ts`,vr(d,u,n)),i||(await g(`domain/entities/${u}.entity.ts`,yr(d,u,n)),await g(`domain/value-objects/${u}-id.vo.ts`,br(d))),await Er(r,d,f,u,c),h}function mr(e,t){return`import { z } from 'zod'
3265
+ `),s}const Sr={string:{ts:`string`,zod:`z.string()`},text:{ts:`string`,zod:`z.string()`},number:{ts:`number`,zod:`z.number()`},int:{ts:`number`,zod:`z.number().int()`},float:{ts:`number`,zod:`z.number()`},boolean:{ts:`boolean`,zod:`z.boolean()`},date:{ts:`string`,zod:`z.string().datetime()`},email:{ts:`string`,zod:`z.string().email()`},url:{ts:`string`,zod:`z.string().url()`},uuid:{ts:`string`,zod:`z.string().uuid()`},json:{ts:`any`,zod:`z.any()`}};function Cr(e){return e.map(e=>{let t=e.indexOf(`:`);if(t===-1)throw Error(`Invalid field: "${e}". Use format: name:type (e.g. title:string)`);let n=e.slice(0,t),r=e.slice(t+1);if(!n||!r)throw Error(`Invalid field: "${e}". Use format: name:type (e.g. title:string)`);let i=!1;r.endsWith(`:optional`)&&(r=r.slice(0,-9),i=!0),n.endsWith(`?`)&&(n=n.slice(0,-1),i=!0),r.endsWith(`?`)&&(r=r.slice(0,-1),i=!0);let a=r;if(a.startsWith(`enum:`)){let e=a.slice(5).split(`,`);return{name:n,type:`enum`,tsType:e.map(e=>`'${e}'`).join(` | `),zodType:`z.enum([${e.map(e=>`'${e}'`).join(`, `)}])`,optional:i}}let o=Sr[a];if(!o){let e=[...Object.keys(Sr),`enum:a,b,c`].join(`, `);throw Error(`Unknown field type: "${a}". Valid types: ${e}`)}return{name:n,type:a,tsType:o.ts,zodType:o.zod,optional:i}})}async function wr(e){let{name:t,fields:n,modulesDir:r,noEntity:i,noTests:a,repo:o=`inmemory`,tokenScope:s=`app`,style:c=`define`}=e,l=e.pluralize!==!1,u=B(t),d=R(t);z(t);let f=l?V(u):u,p=l?Ft(d):d,m=S(r,f),h=[],g=async(e,t)=>{let n=S(m,e);await M(n,t),h.push(n)};await g(`${u}.module.ts`,Mr(d,u,f,c)),await g(`constants.ts`,Or(d,n)),await g(`presentation/${u}.controller.ts`,Nr(d,u,f,p)),await g(`application/dtos/create-${u}.dto.ts`,Tr(d,n)),await g(`application/dtos/update-${u}.dto.ts`,Er(d,n)),await g(`application/dtos/${u}-response.dto.ts`,Dr(d,n));let _=Ir(d,u,f,p);for(let e of _)await g(`application/use-cases/${e.file}`,e.content);return await g(`domain/repositories/${u}.repository.ts`,Pr(d,u,s)),await g(`domain/services/${u}-domain.service.ts`,Fr(d,u)),o===`inmemory`&&await g(`infrastructure/repositories/in-memory-${u}.repository.ts`,kr(d,u,n)),i||(await g(`domain/entities/${u}.entity.ts`,Ar(d,u,n)),await g(`domain/value-objects/${u}-id.vo.ts`,jr(d))),await Fn(r,d,f,u,c),h}function Tr(e,t){return`import { z } from 'zod'
3251
3266
 
3252
3267
  export const create${e}Schema = z.object({
3253
3268
  ${t.map(e=>{let t=e.zodType;return` ${e.name}: ${t}${e.optional?`.optional()`:``},`}).join(`
@@ -3255,7 +3270,7 @@ ${t.map(e=>{let t=e.zodType;return` ${e.name}: ${t}${e.optional?`.optional()`:`
3255
3270
  })
3256
3271
 
3257
3272
  export type Create${e}DTO = z.infer<typeof create${e}Schema>
3258
- `}function hr(e,t){return`import { z } from 'zod'
3273
+ `}function Er(e,t){return`import { z } from 'zod'
3259
3274
 
3260
3275
  export const update${e}Schema = z.object({
3261
3276
  ${t.map(e=>` ${e.name}: ${e.zodType}.optional(),`).join(`
@@ -3263,21 +3278,21 @@ ${t.map(e=>` ${e.name}: ${e.zodType}.optional(),`).join(`
3263
3278
  })
3264
3279
 
3265
3280
  export type Update${e}DTO = z.infer<typeof update${e}Schema>
3266
- `}function gr(e,t){return`export interface ${e}ResponseDTO {
3281
+ `}function Dr(e,t){return`export interface ${e}ResponseDTO {
3267
3282
  id: string
3268
3283
  ${t.map(e=>` ${e.name}${e.optional?`?`:``}: ${e.tsType}`).join(`
3269
3284
  `)}
3270
3285
  createdAt: string
3271
3286
  updatedAt: string
3272
3287
  }
3273
- `}function _r(e,t){let n=t.filter(e=>e.tsType===`string`).map(e=>`'${e.name}'`);t.filter(e=>e.tsType===`number`).map(e=>`'${e.name}'`);let r=t.map(e=>`'${e.name}'`),i=[...r].join(`, `),a=[...r,`'createdAt'`,`'updatedAt'`].join(`, `),o=n.length>0?n.join(`, `):`'name'`;return`import type { ApiQueryParamsConfig } from '@forinda/kickjs'
3288
+ `}function Or(e,t){let n=t.filter(e=>e.tsType===`string`).map(e=>`'${e.name}'`);t.filter(e=>e.tsType===`number`).map(e=>`'${e.name}'`);let r=t.map(e=>`'${e.name}'`),i=[...r].join(`, `),a=[...r,`'createdAt'`,`'updatedAt'`].join(`, `),o=n.length>0?n.join(`, `):`'name'`;return`import type { ApiQueryParamsConfig } from '@forinda/kickjs'
3274
3289
 
3275
3290
  export const ${e.toUpperCase()}_QUERY_CONFIG: ApiQueryParamsConfig = {
3276
3291
  filterable: [${i}],
3277
3292
  sortable: [${a}],
3278
3293
  searchable: [${o}],
3279
3294
  }
3280
- `}function vr(e,t,n){return`import { randomUUID } from 'node:crypto'
3295
+ `}function kr(e,t,n){return`import { randomUUID } from 'node:crypto'
3281
3296
  import { Repository, HttpException } from '@forinda/kickjs'
3282
3297
  import type { ParsedQuery } from '@forinda/kickjs'
3283
3298
  import type { I${e}Repository } from '../../domain/repositories/${t}.repository'
@@ -3329,7 +3344,7 @@ ${n.map(e=>` ${e.name}: dto.${e.name},`).join(`
3329
3344
  this.store.delete(id)
3330
3345
  }
3331
3346
  }
3332
- `}function yr(e,t,n){return`import { ${e}Id } from '../value-objects/${t}-id.vo'
3347
+ `}function Ar(e,t,n){return`import { ${e}Id } from '../value-objects/${t}-id.vo'
3333
3348
 
3334
3349
  interface ${e}Props {
3335
3350
  id: ${e}Id
@@ -3375,7 +3390,7 @@ ${n.map(e=>` ${e.name}: this.props.${e.name},`).join(`
3375
3390
  }
3376
3391
  }
3377
3392
  }
3378
- `}function br(e){return`import { randomUUID } from 'node:crypto'
3393
+ `}function jr(e){return`import { randomUUID } from 'node:crypto'
3379
3394
 
3380
3395
  export class ${e}Id {
3381
3396
  private constructor(private readonly value: string) {}
@@ -3390,7 +3405,7 @@ export class ${e}Id {
3390
3405
  toString(): string { return this.value }
3391
3406
  equals(other: ${e}Id): boolean { return this.value === other.value }
3392
3407
  }
3393
- `}function xr(e,t,n,r=`define`){let i=`import { ${e}Controller } from './presentation/${t}.controller'
3408
+ `}function Mr(e,t,n,r=`define`){let i=`import { ${e}Controller } from './presentation/${t}.controller'
3394
3409
  import { ${e.toUpperCase()}_REPOSITORY } from './domain/repositories/${t}.repository'
3395
3410
  import { InMemory${e}Repository } from './infrastructure/repositories/in-memory-${t}.repository'
3396
3411
 
@@ -3400,10 +3415,13 @@ import.meta.glob(
3400
3415
  ['./domain/services/**/*.ts', './application/use-cases/**/*.ts', '!./**/*.test.ts'],
3401
3416
  { eager: true },
3402
3417
  )`,a=` /**
3403
- * Declare HTTP routes. Pass \`controller\` and the framework
3404
- * derives the Express Router via \`buildRoutes()\`. Return an array
3405
- * to mount multiple route sets each entry can override the API
3406
- * version with a \`version\` field:
3418
+ * Declare HTTP routes for this module. Return value shape:
3419
+ *
3420
+ * - \`path\` URL prefix for this route set.
3421
+ * - \`controller\` — Controller class (also drives OpenAPI).
3422
+ * - \`version\` — Optional. Overrides the app-wide API version.
3423
+ *
3424
+ * Return an array to mount multiple route sets:
3407
3425
  *
3408
3426
  * return [
3409
3427
  * { path: '/${n}', version: 1, controller: ${e}V1Controller },
@@ -3460,7 +3478,7 @@ ${a}
3460
3478
  },
3461
3479
  }),
3462
3480
  })
3463
- `}function Sr(e,t,n,r){return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
3481
+ `}function Nr(e,t,n,r){return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
3464
3482
  import { ApiTags } from '@forinda/kickjs-swagger'
3465
3483
  import { Create${e}UseCase } from '../application/use-cases/create-${t}.use-case'
3466
3484
  import { Get${e}UseCase } from '../application/use-cases/get-${t}.use-case'
@@ -3523,7 +3541,7 @@ export class ${e}Controller {
3523
3541
  ctx.noContent()
3524
3542
  }
3525
3543
  }
3526
- `}function Cr(e,t,n){return`import { createToken } from '@forinda/kickjs'
3544
+ `}function Pr(e,t,n){return`import { createToken } from '@forinda/kickjs'
3527
3545
  import type { ${e}ResponseDTO } from '../../application/dtos/${t}-response.dto'
3528
3546
  import type { Create${e}DTO } from '../../application/dtos/create-${t}.dto'
3529
3547
  import type { Update${e}DTO } from '../../application/dtos/update-${t}.dto'
@@ -3549,7 +3567,7 @@ export interface I${e}Repository {
3549
3567
  * adopters must NOT use the reserved \`'kick/'\` namespace.
3550
3568
  */
3551
3569
  export const ${e.toUpperCase()}_REPOSITORY = createToken<I${e}Repository>('${n}/${e}/repository')
3552
- `}function wr(e,t){return`import { Service, Inject, HttpException } from '@forinda/kickjs'
3570
+ `}function Fr(e,t){return`import { Service, Inject, HttpException } from '@forinda/kickjs'
3553
3571
  import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../repositories/${t}.repository'
3554
3572
 
3555
3573
  @Service()
@@ -3563,7 +3581,7 @@ export class ${e}DomainService {
3563
3581
  if (!entity) throw HttpException.notFound('${e} not found')
3564
3582
  }
3565
3583
  }
3566
- `}function Tr(e,t,n,r){return[{file:`create-${t}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
3584
+ `}function Ir(e,t,n,r){return[{file:`create-${t}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
3567
3585
  import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
3568
3586
  import type { Create${e}DTO } from '../dtos/create-${t}.dto'
3569
3587
 
@@ -3606,10 +3624,7 @@ export class Delete${e}UseCase {
3606
3624
  constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
3607
3625
  async execute(id: string) { return this.repo.delete(id) }
3608
3626
  }
3609
- `}]}async function Er(e,t,n,r,i=`define`){let a=x(e,`index.ts`),o=await Re(a),s=`./${n}/${r}.module`,c=i===`class`?`${t}Module`:`${t}Module()`;if(!o){await j(a,`import type { AppModuleEntry } from '@forinda/kickjs'\nimport { ${t}Module } from '${s}'\n\nexport const modules: AppModuleEntry[] = [${c}]\n`);return}let l=await E(a,`utf-8`),u=`import { ${t}Module } from '${s}'`;if(!l.includes(`${t}Module`)){let e=l.lastIndexOf(`import `);if(e!==-1){let t=l.indexOf(`
3610
- `,e);l=l.slice(0,t+1)+u+`
3611
- `+l.slice(t+1)}else l=u+`
3612
- `+l;l=l.replace(/(=\s*\[)([\s\S]*?)(])/,(e,t,n,r)=>{let i=n.trim();if(!i)return`${t}${c}${r}`;let a=i.endsWith(`,`)?``:`,`;return`${t}${n.trimEnd()}${a} ${c}${r}`})}await D(a,l,`utf-8`)}async function Dr(e){let{name:t,moduleName:n,modulesDir:r}=e,i=e.pluralize??!0,a=B(t),o=R(t),s=[],c;if(e.outDir)c=C(e.outDir);else if(n){let e=B(n),t=i?V(e):e;c=C(x(r??`src/modules`,t,`__tests__`))}else c=C(`src/__tests__`);let l=x(c,`${a}.test.ts`);return await j(l,`import { describe, it, expect, beforeEach } from 'vitest'
3627
+ `}]}async function Lr(e){let{name:t,moduleName:n,modulesDir:r}=e,i=e.pluralize??!0,a=B(t),o=R(t),s=[],c;if(e.outDir)c=w(e.outDir);else if(n){let e=B(n),t=i?V(e):e;c=w(S(r??`src/modules`,t,`__tests__`))}else c=w(`src/__tests__`);let l=S(c,`${a}.test.ts`);return await M(l,`import { describe, it, expect, beforeEach } from 'vitest'
3613
3628
  import { Container } from '@forinda/kickjs'
3614
3629
 
3615
3630
  describe('${o}', () => {
@@ -3632,59 +3647,59 @@ describe('${o}', () => {
3632
3647
  expect(true).toBe(true)
3633
3648
  })
3634
3649
  })
3635
- `),s.push(l),s}const Or=[`agents`,`claude`,`skills`,`both`,`all`];function K(e){return e.parent?.opts()?.dryRun??!1}function q(e,t=!1){let n=process.cwd();console.log(`\n ${t?`Would generate`:`Generated`} ${e.length} file${e.length===1?``:`s`}:`);for(let t of e)console.log(` ${t.replace(n+`/`,``)}`);t&&console.log(`
3636
- (dry run — no files were written)`),console.log()}async function kr(e){if(!e)try{let e=await r(process.cwd());await f({cwd:process.cwd(),allowDuplicates:!0,silent:!0,schemaValidator:e?.typegen?.schemaValidator??`zod`,envFile:e?.typegen?.envFile,srcDir:e?.typegen?.srcDir,outDir:e?.typegen?.outDir})}catch{}}const Ar=[{name:`module <name>`,description:`Full DDD module (controller, DTOs, use-cases, repo)`},{name:`scaffold <name> <fields...>`,description:`CRUD module from field definitions`},{name:`controller <name>`,description:`@Controller() class [-m module]`},{name:`service <name>`,description:`@Service() singleton [-m module]`},{name:`middleware <name>`,description:`Express middleware function [-m module]`},{name:`guard <name>`,description:`Route guard (auth, roles, etc.) [-m module]`},{name:`dto <name>`,description:`Zod DTO schema [-m module]`},{name:`adapter <name>`,description:`AppAdapter with lifecycle hooks (app-level only)`},{name:`test <name>`,description:`Vitest test scaffold [-m module]`},{name:`job <name>`,description:`Queue @Job processor`},{name:`config`,description:`Generate kick.config.ts`},{name:`agents`,description:`Regenerate AGENTS.md + CLAUDE.md + kickjs-skills.md from upstream templates`}];async function jr(){console.log(`
3650
+ `),s.push(l),s}const Rr=[`agents`,`claude`,`skills`,`both`,`all`];function q(e){return e.parent?.opts()?.dryRun??!1}function J(e,t=!1){let n=process.cwd();console.log(`\n ${t?`Would generate`:`Generated`} ${e.length} file${e.length===1?``:`s`}:`);for(let t of e)console.log(` ${t.replace(n+`/`,``)}`);t&&console.log(`
3651
+ (dry run — no files were written)`),console.log()}async function zr(e){if(!e)try{let e=await r(process.cwd());await p({cwd:process.cwd(),allowDuplicates:!0,silent:!0,schemaValidator:e?.typegen?.schemaValidator??`zod`,envFile:e?.typegen?.envFile,srcDir:e?.typegen?.srcDir,outDir:e?.typegen?.outDir})}catch{}}const Br=[{name:`module <name>`,description:`Full DDD module (controller, DTOs, use-cases, repo)`},{name:`scaffold <name> <fields...>`,description:`CRUD module from field definitions`},{name:`controller <name>`,description:`@Controller() class [-m module]`},{name:`service <name>`,description:`@Service() singleton [-m module]`},{name:`middleware <name>`,description:`Express middleware function [-m module]`},{name:`guard <name>`,description:`Route guard (auth, roles, etc.) [-m module]`},{name:`dto <name>`,description:`Zod DTO schema [-m module]`},{name:`adapter <name>`,description:`AppAdapter with lifecycle hooks (app-level only)`},{name:`test <name>`,description:`Vitest test scaffold [-m module]`},{name:`job <name>`,description:`Queue @Job processor`},{name:`config`,description:`Generate kick.config.ts`},{name:`agents`,description:`Regenerate AGENTS.md + CLAUDE.md + kickjs-skills.md from upstream templates`}];async function Vr(){console.log(`
3637
3652
  Built-in generators:
3638
- `);let e=Math.max(...Ar.map(e=>e.name.length));for(let t of Ar)console.log(` kick g ${t.name.padEnd(e+2)} ${t.description}`);let t=await r(process.cwd()),n=a(t?.plugins??[],t?.commands??[]),i=await Vt(process.cwd(),n.generators);if(i.generators.length>0){console.log(`
3653
+ `);let e=Math.max(...Br.map(e=>e.name.length));for(let t of Br)console.log(` kick g ${t.name.padEnd(e+2)} ${t.description}`);let t=await r(process.cwd()),n=a(t?.plugins??[],t?.commands??[]),i=await Kt(process.cwd(),n.generators);if(i.generators.length>0){console.log(`
3639
3654
  Plugin generators:
3640
3655
  `);let e=Math.max(...i.generators.map(e=>`${e.spec.name} <name>`.length));for(let{source:t,spec:n}of i.generators){let r=`${n.name} <name>`;console.log(` kick g ${r.padEnd(e+2)} ${n.description} [${t}]`)}}if(i.failed.length>0){console.log(`
3641
3656
  Failed to load:
3642
- `);for(let{source:e,reason:t}of i.failed)console.log(` ${e} — ${t}`)}console.log()}async function Mr(e,i,a){let o=await r(process.cwd()),s=n(o),c=i.modulesDir??s.dir??`src/modules`,l=i.repo??On(s.repo),u=i.pattern??o?.pattern??`ddd`,d=i.pluralize===!1?!1:s.pluralize??!0,f=t(o,process.cwd()),p=s.style??`define`;if(!a&&p===`define`){let e=await ir(C(c),`define`);if(e.length>0){console.error(`\n ${k.red(`Error:`)} ${e.length} module file(s) still use the legacy \`class … implements AppModule\` shape.\n ${k.dim(`Project setting:`)} modules.style: 'define' (default)\n\n ${k.bold(`Files needing migration:`)}`);for(let t of e.slice(0,5))console.error(` - ${t}`);e.length>5&&console.error(` … and ${e.length-5} more`),console.error(`\n ${k.bold(`Pick one:`)}\n 1. Migrate everything to defineModule:\n ${k.dim(`$`)} kick codemod modules --experimental --apply\n 2. Keep the class form — pin it in kick.config.ts:\n ${k.dim(`// kick.config.ts`)}\n ${k.dim(`export default defineConfig({ modules: { style: 'class' } })`)}\n`),process.exit(1)}}let m=[];for(let t of e){let e=await kn({name:t,modulesDir:C(c),noEntity:i.entity===!1,noTests:i.tests===!1,repo:l,minimal:i.minimal,force:i.force,pattern:u,dryRun:a,pluralize:d,prismaClientPath:s.prismaClientPath,tokenScope:f,style:s.style});m.push(...e)}q(m,a),await kr(a)}function Nr(e){let i=e.command(`generate [names...]`).alias(`g`).description("Generate code scaffolds — bare form `kick g <name>` is shorthand for `kick g module <name>`").option(`--list`,`List all available generators`).option(`--dry-run`,`Preview files that would be generated without writing them`).option(`--no-entity`,`Skip entity and value object generation (module shortcut)`).option(`--no-tests`,`Skip test file generation (module shortcut)`).option(`--repo <type>`,`Repository implementation: inmemory | drizzle | prisma`).option(`--pattern <pattern>`,`Override project pattern: rest | ddd | cqrs | minimal`).option(`--minimal`,`Shorthand for --pattern minimal`).option(`--modules-dir <dir>`,`Modules directory`).option(`--no-pluralize`,`Use singular names (skip auto-pluralization)`).option(`-f, --force`,`Overwrite existing files without prompting`).action(async(e,t,n)=>{if(t.list){await jr();return}if(!e||e.length===0){i.help();return}let o=K(n);if(A(o),e.length>=2){let[n,i,...s]=e,c=await r(process.cwd()),l=a(c?.plugins??[],c?.commands??[]),u=await Bt({generatorName:n,itemName:i,args:s,flags:t,cwd:process.cwd()},l.generators);if(u){q(u.files,o);return}}await Mr(e,t,o)});i.command(`module <names...>`).description(`Generate one or more modules (e.g. kick g module user task project)`).option(`--no-entity`,`Skip entity and value object generation`).option(`--no-tests`,`Skip test file generation`).option(`--repo <type>`,`Repository implementation: inmemory | drizzle | prisma`).option(`--pattern <pattern>`,`Override project pattern: rest | ddd | cqrs | minimal`).option(`--minimal`,`Shorthand for --pattern minimal`).option(`--modules-dir <dir>`,`Modules directory`).option(`--no-pluralize`,`Use singular names (skip auto-pluralization)`).option(`-f, --force`,`Overwrite existing files without prompting`).action(async(e,t,n)=>{let r=K(n);A(r),await Mr(e,t,r)}),i.command(`adapter <name>`).description(`Generate an AppAdapter with lifecycle hooks and middleware support`).option(`-o, --out <dir>`,`Output directory`,`src/adapters`).action(async(e,t,n)=>{let r=K(n);A(r),q(await jn({name:e,outDir:C(t.out)}),r)}),i.command(`plugin <name>`).description(`Generate a KickPlugin with DI, modules, adapters, middleware, and lifecycle hooks`).option(`-o, --out <dir>`,`Output directory`,`src/plugins`).action(async(e,t,n)=>{let r=K(n);A(r),q(await Mn({name:e,outDir:C(t.out)}),r)}),i.command(`middleware <name>`).description(`Generate an Express middleware function
3643
- Use -m to scope it to a module: kick g middleware auth -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,i)=>{let a=K(i);A(a);let o=await r(process.cwd()),s=n(o),c=s.dir??`src/modules`;q(await In({name:e,outDir:t.out,moduleName:t.module,modulesDir:c,pattern:o?.pattern,pluralize:s.pluralize??!0}),a)}),i.command(`guard <name>`).description(`Generate a route guard (auth, roles, etc.)
3644
- Use -m to scope it to a module: kick g guard admin -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,i)=>{let a=K(i);A(a);let o=await r(process.cwd()),s=n(o),c=s.dir??`src/modules`;q(await Ln({name:e,outDir:t.out,moduleName:t.module,modulesDir:c,pattern:o?.pattern,pluralize:s.pluralize??!0}),a)}),i.command(`service <name>`).description(`Generate a @Service() class
3645
- Use -m to scope it to a module: kick g service payment -m orders`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,i)=>{let a=K(i);A(a);let o=await r(process.cwd()),s=n(o),c=s.dir??`src/modules`;q(await Rn({name:e,outDir:t.out,moduleName:t.module,modulesDir:c,pattern:o?.pattern,pluralize:s.pluralize??!0}),a)}),i.command(`controller <name>`).description(`Generate a @Controller() class with basic routes
3646
- Use -m to scope it to a module: kick g controller auth -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,i)=>{let a=K(i);A(a);let o=await r(process.cwd()),s=n(o),c=s.dir??`src/modules`;q(await zn({name:e,outDir:t.out,moduleName:t.module,modulesDir:c,pattern:o?.pattern,pluralize:s.pluralize??!0}),a),await kr(a)}),i.command(`dto <name>`).description(`Generate a Zod DTO schema
3647
- Use -m to scope it to a module: kick g dto create-user -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,i)=>{let a=K(i);A(a);let o=await r(process.cwd()),s=n(o),c=s.dir??`src/modules`;q(await Bn({name:e,outDir:t.out,moduleName:t.module,modulesDir:c,pattern:o?.pattern,pluralize:s.pluralize??!0}),a)}),i.command(`test <name>`).description(`Generate a Vitest test scaffold
3648
- Use -m to scope it to a module: kick g test user-service -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module's __tests__/ folder`).action(async(e,t,i)=>{let a=K(i);A(a);let o=n(await r(process.cwd())),s=o.dir??`src/modules`;q(await Dr({name:e,outDir:t.out,moduleName:t.module,modulesDir:s,pluralize:o.pluralize??!0}),a)}),i.command(`job <name>`).description(`Generate a @Job queue processor with @Process handlers`).option(`-o, --out <dir>`,`Output directory`,`src/jobs`).option(`-q, --queue <name>`,`Queue name (default: <name>-queue)`).action(async(e,t,n)=>{let r=K(n);A(r),q(await ur({name:e,outDir:C(t.out),queue:t.queue}),r)}),i.command(`scaffold <name> [fields...]`).description(`Generate a full CRUD module from field definitions
3657
+ `);for(let{source:e,reason:t}of i.failed)console.log(` ${e} — ${t}`)}console.log()}async function Hr(e,i,a){let o=await r(process.cwd()),s=n(o),c=i.modulesDir??s.dir??`src/modules`,l=i.repo??Nn(s.repo),u=i.pattern??o?.pattern??`ddd`,d=i.pluralize===!1?!1:s.pluralize??!0,f=t(o,process.cwd()),p=s.style??`define`;if(!a&&p===`define`){let e=await hr(w(c),`define`);if(e.length>0){console.error(`\n ${A.red(`Error:`)} ${e.length} module file(s) still use the legacy \`class … implements AppModule\` shape.\n ${A.dim(`Project setting:`)} modules.style: 'define' (default)\n\n ${A.bold(`Files needing migration:`)}`);for(let t of e.slice(0,5))console.error(` - ${t}`);e.length>5&&console.error(` … and ${e.length-5} more`),console.error(`\n ${A.bold(`Pick one:`)}\n 1. Migrate everything to defineModule:\n ${A.dim(`$`)} kick codemod modules --experimental --apply\n 2. Keep the class form — pin it in kick.config.ts:\n ${A.dim(`// kick.config.ts`)}\n ${A.dim(`export default defineConfig({ modules: { style: 'class' } })`)}\n`),process.exit(1)}}let m=[];for(let t of e){let e=await Pn({name:t,modulesDir:w(c),noEntity:i.entity===!1,noTests:i.tests===!1,repo:l,minimal:i.minimal,force:i.force,pattern:u,dryRun:a,pluralize:d,prismaClientPath:s.prismaClientPath,tokenScope:f,style:s.style});m.push(...e)}J(m,a),await zr(a)}function Ur(e){let i=e.command(`generate [names...]`).alias(`g`).description("Generate code scaffolds — bare form `kick g <name>` is shorthand for `kick g module <name>`").option(`--list`,`List all available generators`).option(`--dry-run`,`Preview files that would be generated without writing them`).option(`--no-entity`,`Skip entity and value object generation (module shortcut)`).option(`--no-tests`,`Skip test file generation (module shortcut)`).option(`--repo <type>`,`Repository implementation: inmemory | drizzle | prisma`).option(`--pattern <pattern>`,`Override project pattern: rest | ddd | cqrs | minimal`).option(`--minimal`,`Shorthand for --pattern minimal`).option(`--modules-dir <dir>`,`Modules directory`).option(`--no-pluralize`,`Use singular names (skip auto-pluralization)`).option(`-f, --force`,`Overwrite existing files without prompting`).action(async(e,t,n)=>{if(t.list){await Vr();return}if(!e||e.length===0){i.help();return}let o=q(n);if(j(o),e.length>=2){let[n,i,...s]=e,c=await r(process.cwd()),l=a(c?.plugins??[],c?.commands??[]),u=await Gt({generatorName:n,itemName:i,args:s,flags:t,cwd:process.cwd()},l.generators);if(u){J(u.files,o);return}}await Hr(e,t,o)});i.command(`module <names...>`).description(`Generate one or more modules (e.g. kick g module user task project)`).option(`--no-entity`,`Skip entity and value object generation`).option(`--no-tests`,`Skip test file generation`).option(`--repo <type>`,`Repository implementation: inmemory | drizzle | prisma`).option(`--pattern <pattern>`,`Override project pattern: rest | ddd | cqrs | minimal`).option(`--minimal`,`Shorthand for --pattern minimal`).option(`--modules-dir <dir>`,`Modules directory`).option(`--no-pluralize`,`Use singular names (skip auto-pluralization)`).option(`-f, --force`,`Overwrite existing files without prompting`).action(async(e,t,n)=>{let r=q(n);j(r),await Hr(e,{...n.optsWithGlobals(),...t},r)}),i.command(`adapter <name>`).description(`Generate an AppAdapter with lifecycle hooks and middleware support`).option(`-o, --out <dir>`,`Output directory`,`src/adapters`).action(async(e,t,n)=>{let r=q(n);j(r),J(await Hn({name:e,outDir:w(t.out)}),r)}),i.command(`plugin <name>`).description(`Generate a KickPlugin with DI, modules, adapters, middleware, and lifecycle hooks`).option(`-o, --out <dir>`,`Output directory`,`src/plugins`).action(async(e,t,n)=>{let r=q(n);j(r),J(await Un({name:e,outDir:w(t.out)}),r)}),i.command(`middleware <name>`).description(`Generate an Express middleware function
3658
+ Use -m to scope it to a module: kick g middleware auth -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,i)=>{let a=q(i);j(a);let o=await r(process.cwd()),s=n(o),c=s.dir??`src/modules`;J(await qn({name:e,outDir:t.out,moduleName:t.module,modulesDir:c,pattern:o?.pattern,pluralize:s.pluralize??!0}),a)}),i.command(`guard <name>`).description(`Generate a route guard (auth, roles, etc.)
3659
+ Use -m to scope it to a module: kick g guard admin -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,i)=>{let a=q(i);j(a);let o=await r(process.cwd()),s=n(o),c=s.dir??`src/modules`;J(await Jn({name:e,outDir:t.out,moduleName:t.module,modulesDir:c,pattern:o?.pattern,pluralize:s.pluralize??!0}),a)}),i.command(`service <name>`).description(`Generate a @Service() class
3660
+ Use -m to scope it to a module: kick g service payment -m orders`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,i)=>{let a=q(i);j(a);let o=await r(process.cwd()),s=n(o),c=s.dir??`src/modules`;J(await Yn({name:e,outDir:t.out,moduleName:t.module,modulesDir:c,pattern:o?.pattern,pluralize:s.pluralize??!0}),a)}),i.command(`controller <name>`).description(`Generate a @Controller() class with basic routes
3661
+ Use -m to scope it to a module: kick g controller auth -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,i)=>{let a=q(i);j(a);let o=await r(process.cwd()),s=n(o),c=s.dir??`src/modules`;J(await Xn({name:e,outDir:t.out,moduleName:t.module,modulesDir:c,pattern:o?.pattern,pluralize:s.pluralize??!0}),a),await zr(a)}),i.command(`dto <name>`).description(`Generate a Zod DTO schema
3662
+ Use -m to scope it to a module: kick g dto create-user -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,i)=>{let a=q(i);j(a);let o=await r(process.cwd()),s=n(o),c=s.dir??`src/modules`;J(await Zn({name:e,outDir:t.out,moduleName:t.module,modulesDir:c,pattern:o?.pattern,pluralize:s.pluralize??!0}),a)}),i.command(`test <name>`).description(`Generate a Vitest test scaffold
3663
+ Use -m to scope it to a module: kick g test user-service -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module's __tests__/ folder`).action(async(e,t,i)=>{let a=q(i);j(a);let o=n(await r(process.cwd())),s=o.dir??`src/modules`;J(await Lr({name:e,outDir:t.out,moduleName:t.module,modulesDir:s,pluralize:o.pluralize??!0}),a)}),i.command(`job <name>`).description(`Generate a @Job queue processor with @Process handlers`).option(`-o, --out <dir>`,`Output directory`,`src/jobs`).option(`-q, --queue <name>`,`Queue name (default: <name>-queue)`).action(async(e,t,n)=>{let r=q(n);j(r),J(await xr({name:e,outDir:w(t.out),queue:t.queue}),r)}),i.command(`scaffold <name> [fields...]`).description(`Generate a full CRUD module from field definitions
3649
3664
  Example: kick g scaffold Post title:string body:text:optional published:boolean:optional
3650
3665
  Types: string, text, number, int, float, boolean, date, email, url, uuid, json, enum:a,b,c
3651
3666
  Optional: append :optional (shell-safe): description:text:optional
3652
- or use ? with quoting: "description:text?" or "description?:text"`).option(`--no-entity`,`Skip entity and value object generation`).option(`--no-tests`,`Skip test file generation`).option(`--no-pluralize`,`Use singular names (skip auto-pluralization)`).option(`--modules-dir <dir>`,`Modules directory`).action(async(e,i,a,o)=>{let s=K(o);A(s),i.length===0&&(console.error(`
3667
+ or use ? with quoting: "description:text?" or "description?:text"`).option(`--no-entity`,`Skip entity and value object generation`).option(`--no-tests`,`Skip test file generation`).option(`--no-pluralize`,`Use singular names (skip auto-pluralization)`).option(`--modules-dir <dir>`,`Modules directory`).action(async(e,i,a,o)=>{let s=q(o);j(s),i.length===0&&(console.error(`
3653
3668
  Error: At least one field is required.
3654
3669
  Usage: kick g scaffold <name> <field:type> [field:type...]
3655
3670
  Example: kick g scaffold Post title:string body:text:optional published:boolean:optional
3656
3671
  Optional: append :optional (shell-safe, no quoting needed)
3657
- `),process.exit(1));let c=await r(process.cwd()),l=n(c),u=a.modulesDir??l.dir??`src/modules`,d=fr(i),f=t(c,process.cwd()),p=c?.pattern??`ddd`;p!==`ddd`&&(console.error(`\n Error: 'kick g scaffold' currently only supports the DDD pattern.\n Detected project pattern: '${p}'.\n Workarounds:\n - Run 'kick g module ${e}' for the ${p} layout (no fields), then add fields manually.\n - Override the pattern for this scaffold by setting kick.config.ts pattern: 'ddd'.\n`),process.exit(1));let m=await pr({name:e,fields:d,modulesDir:C(u),noEntity:a.entity===!1,noTests:a.tests===!1,pluralize:a.pluralize===!1?!1:l.pluralize??!0,tokenScope:f,style:l.style});console.log(`\n Scaffolded ${e} with ${d.length} field(s):`);for(let e of d)console.log(` ${e.name}: ${e.type}${e.optional?` (optional)`:``}`);q(m,s),await kr(s)}),i.command(`auth-scaffold`).description(`Generate a complete auth module (register, login, logout, password hashing)
3658
- Includes controller, service, DTOs, and test stubs.`).option(`-s, --strategy <type>`,`Auth strategy: jwt | session`).option(`--role-guards`,`Generate role-based guards (default: true)`).option(`--no-role-guards`,`Skip role-based guard generation`).option(`-o, --out <dir>`,`Output directory`,`src/modules/auth`).action(async(e,t)=>{let n=K(t);A(n);let r=e.strategy;r||=await _t({message:`Auth strategy`,options:[{value:`jwt`,label:`JWT`,hint:`stateless token-based auth`},{value:`session`,label:`Session`,hint:`server-side session with cookies`}]});let i=e.roleGuards;i===void 0&&(i=await F({message:`Generate role-based guards?`,initialValue:!0})),q(await ar({strategy:r,outDir:e.out,roleGuards:i}),n)}),i.command(`config`).description(`Generate a kick.config.ts at the project root`).option(`--modules-dir <dir>`,`Modules directory path`,`src/modules`).option(`--repo <type>`,`Default repository type: inmemory | drizzle | prisma`,`inmemory`).option(`-f, --force`,`Overwrite existing kick.config.ts without prompting`).action(async(e,t)=>{let n=K(t);A(n),q(await Vn({outDir:C(`.`),modulesDir:e.modulesDir,defaultRepo:e.repo,force:e.force}),n)}),i.command(`agents`).alias(`agent-docs`).alias(`ai-docs`).description(`Regenerate AGENTS.md + CLAUDE.md + kickjs-skills.md (sync after framework upgrades)`).option(`--only <which>`,`Limit scope: agents | claude | skills | both (agents+claude) | all (default: all)`,`all`).option(`--name <name>`,`Project name (defaults to package.json name)`).option(`--pm <pm>`,`Package manager (defaults to package.json packageManager)`).option(`--template <template>`,`Template: rest | ddd | cqrs | minimal`).option(`-f, --force`,`Overwrite existing files without prompting`).action(async(e,t)=>{let n=K(t);A(n);let r=e.only??`all`;if(!Or.includes(r)){console.error(` Invalid --only value: ${r}. Expected: ${Or.join(` | `)}`),process.exitCode=1;return}q(await Kn({outDir:C(`.`),only:r,name:e.name,pm:e.pm,template:e.template,force:e.force}),n)})}async function Pr(e){let t=y.resolve(e.cwd,`.kickjs/types`);await pe(t,{recursive:!0});let n=new Map,r=e.scan??d,i={cwd:e.cwd,config:e.config,async importTs(e){return await import(w(e).href)},async writeFile(t,n){let r=y.resolve(e.cwd,t);await pe(y.dirname(r),{recursive:!0}),await D(r,n,`utf8`)},getScanResult:e=>{let t=Fr(e),i=n.get(t);return i||(i=r(e),n.set(t,i)),i},log:console},a=[];for(let n of e.plugins){let r=await n.generate(i);if(r===null){a.push({id:n.id,status:`skipped`});continue}let o=n.outExtension??`.d.ts`,s=y.join(t,`${n.id.replace(/\//g,`__`)}${o}`),c=`/* AUTO-GENERATED by kick typegen — do not edit. Plugin: ${n.id} */\n\n`+r+`
3659
- `,l=``;if(h(s)&&(l=await E(s,`utf8`)),l===c){a.push({id:n.id,status:`unchanged`,outFile:s});continue}if(e.check)throw Error(`kick typegen --check: drift detected for ${n.id} (${s})`);await D(s,c,`utf8`),a.push({id:n.id,status:`written`,outFile:s})}return a}function Fr(e){let t=(e.extensions??[]).slice().toSorted().join(`,`),n=(e.exclude??[]).slice().toSorted().join(`,`);return[`root=${e.root}`,`cwd=${e.cwd}`,`extensions=${t}`,`exclude=${n}`,`envFile=${e.envFile??``}`].join(`|`)}function Ir(e,t){let n=new Set(t),r=[],i=[],a=new Set;for(let t of e)n.has(t.id)?(i.push(t),a.add(t.id)):r.push(t);return{enabled:r,skipped:i,unknown:[...n].filter(e=>!a.has(e))}}var Lr=e({applyDisableFilter:()=>Ir,runAllPluginTypegens:()=>Rr});async function Rr(e){let{enabled:t,skipped:n,unknown:r}=Ir(a([..._a,...e.config?.plugins??[]],e.config?.commands??[]).typegens,e.config?.typegen?.disable??[]);if(!e.silent&&n.length>0)for(let e of n)console.log(` ${e.id}: disabled (typegen.disable)`);if(!e.silent&&r.length>0&&console.warn(` kick typegen: disable list references unknown id(s): ${r.map(e=>`'${e}'`).join(`, `)}. Run \`kick typegen --list\` to see registered ids.`),t.length===0)return[];try{let n=await Pr({cwd:e.cwd,config:e.config??{},plugins:t,check:e.check});if(!e.silent)for(let e of n)console.log(` ${e.id}: ${e.status}`);return n}catch(t){if(!e.silent){let e=t instanceof Error?t.message:String(t);console.warn(` kick typegen plugins: skipped (${e})`)}return[]}}async function zr(e,t){let{cwd:n,silent:r=!1}=t,i=t.distDir??e?.build?.outDir??`dist`,a=e?.assetMap;if(!a||Object.keys(a).length===0)return null;let o=r?()=>{}:console.log,s=C(n,i);g(s,{recursive:!0});let c=[],l={};for(let[e,t]of Object.entries(a)){let r=await Br(e,t,n,s);c.push(r.entrySummary),Object.assign(l,r.manifestSlice),o(` ✓ ${e}: ${r.entrySummary.filesCopied} file(s) → ${r.entrySummary.dest}`)}let u={version:1,entries:l},d=x(s,`.kickjs-assets.json`);return ne(d,JSON.stringify(u,null,2)+`
3660
- `,`utf-8`),o(` ✓ wrote manifest → ${S(n,d)} (${Object.keys(l).length} entries)`),{manifestPath:d,entries:c,manifest:u}}async function Br(e,t,n,r){let i=C(n,t.src),a=t.dest?C(n,t.dest):x(r,e);if(Hr(a,n))return console.warn(` ⚠ assetMap.${e}.dest ('${t.dest}') resolves outside the project root — skipping copy`),{entrySummary:{namespace:e,src:t.src,dest:S(n,a),filesCopied:0},manifestSlice:{}};if(!h(i)||!Ur(i))return{entrySummary:{namespace:e,src:t.src,dest:S(n,a),filesCopied:0},manifestSlice:{}};let o=await ve(t.glob??`**/*`,{cwd:i,nodir:!0,dot:!1,posix:!0});g(a,{recursive:!0});let s={},{pairs:c,collisionGroupsResolved:l}=ye(e,[...o].toSorted(),{strategy:t.keys??`auto`});for(let{rel:e,key:t}of c){let n=x(i,e),o=x(a,e);g(b(o),{recursive:!0}),m(n,o),s[t]=Vr(r,o)}return l>0&&console.log(` ℹ assetMap.${e}: auto-resolved ${l} basename collision(s) by keeping extensions (set 'keys: "strip"' to opt back into legacy last-write-wins behaviour, or 'keys: "with-extension"' to keep all keys verbose).`),{entrySummary:{namespace:e,src:t.src,dest:S(n,a),filesCopied:o.length},manifestSlice:s}}function Vr(e,t){return S(e,t).split(/[\\/]/).filter(Boolean).join(`/`)}function Hr(e,t){let n=S(t,e);return n===``?!1:n.startsWith(`..`)||ae(n)}function Ur(e){try{return te(e).isDirectory()}catch{return!1}}function Wr(e){if(typeof e==`boolean`)return e;let t=process.env.KICKJS_WATCH_POLLING;return t===`1`||t===`true`}async function Gr(e,t,n={}){t&&(process.env.PORT=t);let i=Wr(n.polling),a=process.cwd(),o=await r(a),s=o?.typegen?.schemaValidator??`zod`,c=o?.typegen?.envFile;try{await f({cwd:a,allowDuplicates:!0,schemaValidator:s,envFile:c,srcDir:o?.typegen?.srcDir,outDir:o?.typegen?.outDir,assetMap:o?.assetMap,runPlugins:!1})}catch(e){console.warn(` kick typegen: skipped (${e?.message??e})`)}await Rr({cwd:a,config:o});let{createRequire:l}=await import(`node:module`),{createServer:u}=await import(w(l(C(`package.json`)).resolve(`vite`)).href),d=await u({configFile:C(`vite.config.ts`),server:{port:t?parseInt(t,10):void 0,...i?{watch:{usePolling:!0,interval:100}}:{}}}),p=o?.assetMap?Object.values(o.assetMap).map(e=>e?.src).filter(e=>typeof e==`string`&&e.length>0).map(e=>C(a,e)):[],m=e=>p.some(t=>e===t||e.startsWith(`${t}/`)),h=null,g=e=>{if(e.includes(`.kickjs`)||e.endsWith(`.d.ts`))return;let t=/\.(ts|tsx|mts|cts)$/.test(e),n=m(e);!t&&!n||(h&&clearTimeout(h),h=setTimeout(()=>{f({cwd:a,silent:!0,allowDuplicates:!0,schemaValidator:s,envFile:c,srcDir:o?.typegen?.srcDir,outDir:o?.typegen?.outDir,assetMap:o?.assetMap,runPlugins:!1}).catch(()=>{}),Rr({cwd:a,config:o,silent:!0}).catch(()=>{})},100))};d.watcher.on(`add`,g),d.watcher.on(`unlink`,g),d.watcher.on(`change`,g),p.length>0&&d.watcher.add(p),await d.listen(),d.printUrls(),console.log(`
3672
+ `),process.exit(1));let c=await r(process.cwd()),l=n(c),u=a.modulesDir??l.dir??`src/modules`,d=Cr(i),f=t(c,process.cwd()),p=c?.pattern??`ddd`;p!==`ddd`&&(console.error(`\n Error: 'kick g scaffold' currently only supports the DDD pattern.\n Detected project pattern: '${p}'.\n Workarounds:\n - Run 'kick g module ${e}' for the ${p} layout (no fields), then add fields manually.\n - Override the pattern for this scaffold by setting kick.config.ts pattern: 'ddd'.\n`),process.exit(1));let m=await wr({name:e,fields:d,modulesDir:w(u),noEntity:a.entity===!1,noTests:a.tests===!1,pluralize:a.pluralize===!1?!1:l.pluralize??!0,tokenScope:f,style:l.style});console.log(`\n Scaffolded ${e} with ${d.length} field(s):`);for(let e of d)console.log(` ${e.name}: ${e.type}${e.optional?` (optional)`:``}`);J(m,s),await zr(s)}),i.command(`auth-scaffold`).description(`Generate a complete auth module (register, login, logout, password hashing)
3673
+ Includes controller, service, DTOs, and test stubs.`).option(`-s, --strategy <type>`,`Auth strategy: jwt | session`).option(`--role-guards`,`Generate role-based guards (default: true)`).option(`--no-role-guards`,`Skip role-based guard generation`).option(`-o, --out <dir>`,`Output directory`,`src/modules/auth`).action(async(e,t)=>{let n=q(t);j(n);let r=e.strategy;r||=await St({message:`Auth strategy`,options:[{value:`jwt`,label:`JWT`,hint:`stateless token-based auth`},{value:`session`,label:`Session`,hint:`server-side session with cookies`}]});let i=e.roleGuards;i===void 0&&(i=await F({message:`Generate role-based guards?`,initialValue:!0})),J(await gr({strategy:r,outDir:e.out,roleGuards:i}),n)}),i.command(`config`).description(`Generate a kick.config.ts at the project root`).option(`--modules-dir <dir>`,`Modules directory path`,`src/modules`).option(`--repo <type>`,`Default repository type: inmemory | drizzle | prisma`,`inmemory`).option(`-f, --force`,`Overwrite existing kick.config.ts without prompting`).action(async(e,t)=>{let n=q(t);j(n),J(await Qn({outDir:w(`.`),modulesDir:e.modulesDir,defaultRepo:e.repo,force:e.force}),n)}),i.command(`agents`).alias(`agent-docs`).alias(`ai-docs`).description(`Regenerate AGENTS.md + CLAUDE.md + kickjs-skills.md (sync after framework upgrades)`).option(`--only <which>`,`Limit scope: agents | claude | skills | both (agents+claude) | all (default: all)`,`all`).option(`--name <name>`,`Project name (defaults to package.json name)`).option(`--pm <pm>`,`Package manager (defaults to package.json packageManager)`).option(`--template <template>`,`Template: rest | ddd | cqrs | minimal`).option(`-f, --force`,`Overwrite existing files without prompting`).action(async(e,t)=>{let n=q(t);j(n);let r=e.only??`all`;if(!Rr.includes(r)){console.error(` Invalid --only value: ${r}. Expected: ${Rr.join(` | `)}`),process.exitCode=1;return}J(await rr({outDir:w(`.`),only:r,name:e.name,pm:e.pm,template:e.template,force:e.force}),n)})}async function Wr(e){let t=b.resolve(e.cwd,`.kickjs/types`);await me(t,{recursive:!0});let n=new Map,r=e.scan??c,i={cwd:e.cwd,config:e.config,async importTs(e){return await import(T(e).href)},async writeFile(t,n){let r=b.resolve(e.cwd,t);await me(b.dirname(r),{recursive:!0}),await O(r,n,`utf8`)},getScanResult:e=>{let t=Gr(e),i=n.get(t);return i||(i=r(e),n.set(t,i)),i},log:console},a=[];for(let n of e.plugins){let r=await n.generate(i);if(r===null){a.push({id:n.id,status:`skipped`});continue}let o=n.outExtension??`.d.ts`,s=b.join(t,`${n.id.replace(/\//g,`__`)}${o}`),c=`/* AUTO-GENERATED by kick typegen — do not edit. Plugin: ${n.id} */\n\n`+r+`
3674
+ `,l=``;if(g(s)&&(l=await D(s,`utf8`)),l===c){a.push({id:n.id,status:`unchanged`,outFile:s});continue}if(e.check)throw Error(`kick typegen --check: drift detected for ${n.id} (${s})`);await O(s,c,`utf8`),a.push({id:n.id,status:`written`,outFile:s})}return a}function Gr(e){let t=(e.extensions??[]).slice().toSorted().join(`,`),n=(e.exclude??[]).slice().toSorted().join(`,`);return[`root=${e.root}`,`cwd=${e.cwd}`,`extensions=${t}`,`exclude=${n}`,`envFile=${e.envFile??``}`].join(`|`)}function Kr(e,t){let n=new Set(t),r=[],i=[],a=new Set;for(let t of e)n.has(t.id)?(i.push(t),a.add(t.id)):r.push(t);return{enabled:r,skipped:i,unknown:[...n].filter(e=>!a.has(e))}}var qr=e({applyDisableFilter:()=>Kr,runAllPluginTypegens:()=>Jr});async function Jr(e){let{enabled:t,skipped:n,unknown:r}=Kr(a([...Aa,...e.config?.plugins??[]],e.config?.commands??[]).typegens,e.config?.typegen?.disable??[]);if(!e.silent&&n.length>0)for(let e of n)console.log(` ${e.id}: disabled (typegen.disable)`);if(!e.silent&&r.length>0&&console.warn(` kick typegen: disable list references unknown id(s): ${r.map(e=>`'${e}'`).join(`, `)}. Run \`kick typegen --list\` to see registered ids.`),t.length===0)return[];try{let n=await Wr({cwd:e.cwd,config:e.config??{},plugins:t,check:e.check});if(!e.silent)for(let e of n)console.log(` ${e.id}: ${e.status}`);return n}catch(t){if(!e.silent){let e=t instanceof Error?t.message:String(t);console.warn(` kick typegen plugins: skipped (${e})`)}return[]}}async function Yr(e,t){let{cwd:n,silent:r=!1}=t,i=t.distDir??e?.build?.outDir??`dist`,a=e?.assetMap;if(!a||Object.keys(a).length===0)return null;let o=r?()=>{}:console.log,s=w(n,i);_(s,{recursive:!0});let c=[],l={};for(let[e,t]of Object.entries(a)){let r=await Xr(e,t,n,s);c.push(r.entrySummary),Object.assign(l,r.manifestSlice),o(` ✓ ${e}: ${r.entrySummary.filesCopied} file(s) → ${r.entrySummary.dest}`)}let u={version:1,entries:l},d=S(s,`.kickjs-assets.json`);return ne(d,JSON.stringify(u,null,2)+`
3675
+ `,`utf-8`),o(` ✓ wrote manifest → ${C(n,d)} (${Object.keys(l).length} entries)`),{manifestPath:d,entries:c,manifest:u}}async function Xr(e,t,n,r){let i=w(n,t.src),a=t.dest?w(n,t.dest):S(r,e);if(Qr(a,n))return console.warn(` ⚠ assetMap.${e}.dest ('${t.dest}') resolves outside the project root — skipping copy`),{entrySummary:{namespace:e,src:t.src,dest:C(n,a),filesCopied:0},manifestSlice:{}};if(!g(i)||!$r(i))return{entrySummary:{namespace:e,src:t.src,dest:C(n,a),filesCopied:0},manifestSlice:{}};let o=await ye(t.glob??`**/*`,{cwd:i,nodir:!0,dot:!1,posix:!0});_(a,{recursive:!0});let s={},{pairs:c,collisionGroupsResolved:l}=be(e,[...o].toSorted(),{strategy:t.keys??`auto`});for(let{rel:e,key:t}of c){let n=S(i,e),o=S(a,e);_(x(o),{recursive:!0}),h(n,o),s[t]=Zr(r,o)}return l>0&&console.log(` ℹ assetMap.${e}: auto-resolved ${l} basename collision(s) by keeping extensions (set 'keys: "strip"' to opt back into legacy last-write-wins behaviour, or 'keys: "with-extension"' to keep all keys verbose).`),{entrySummary:{namespace:e,src:t.src,dest:C(n,a),filesCopied:o.length},manifestSlice:s}}function Zr(e,t){return C(e,t).split(/[\\/]/).filter(Boolean).join(`/`)}function Qr(e,t){let n=C(t,e);return n===``?!1:n.startsWith(`..`)||ae(n)}function $r(e){try{return te(e).isDirectory()}catch{return!1}}function ei(e){if(typeof e==`boolean`)return e;let t=process.env.KICKJS_WATCH_POLLING;return t===`1`||t===`true`}async function ti(e,t,n={}){t&&(process.env.PORT=t);let i=ei(n.polling),a=process.cwd(),o=await r(a),s=o?.typegen?.schemaValidator??`zod`,c=o?.typegen?.envFile;try{await p({cwd:a,allowDuplicates:!0,schemaValidator:s,envFile:c,srcDir:o?.typegen?.srcDir,outDir:o?.typegen?.outDir,assetMap:o?.assetMap,runPlugins:!1})}catch(e){console.warn(` kick typegen: skipped (${e?.message??e})`)}await Jr({cwd:a,config:o});let{createRequire:l}=await import(`node:module`),{createServer:u}=await import(T(l(w(`package.json`)).resolve(`vite`)).href),d=await u({configFile:w(`vite.config.ts`),server:{port:t?parseInt(t,10):void 0,...i?{watch:{usePolling:!0,interval:100}}:{}}}),f=o?.assetMap?Object.values(o.assetMap).map(e=>e?.src).filter(e=>typeof e==`string`&&e.length>0).map(e=>w(a,e)):[],m=e=>f.some(t=>e===t||e.startsWith(`${t}/`)),h=null,g=e=>{if(e.includes(`.kickjs`)||e.endsWith(`.d.ts`))return;let t=/\.(ts|tsx|mts|cts)$/.test(e),n=m(e);!t&&!n||(h&&clearTimeout(h),h=setTimeout(()=>{p({cwd:a,silent:!0,allowDuplicates:!0,schemaValidator:s,envFile:c,srcDir:o?.typegen?.srcDir,outDir:o?.typegen?.outDir,assetMap:o?.assetMap,runPlugins:!1}).catch(()=>{}),Jr({cwd:a,config:o,silent:!0}).catch(()=>{})},100))};d.watcher.on(`add`,g),d.watcher.on(`unlink`,g),d.watcher.on(`change`,g),f.length>0&&d.watcher.add(f),await d.listen(),d.printUrls(),console.log(`
3661
3676
  KickJS dev server running (Vite + @forinda/kickjs-vite)
3662
- `);let _=async()=>{h&&clearTimeout(h),await d.close(),process.exit(0)};process.on(`SIGINT`,_),process.on(`SIGTERM`,_)}function Kr(e){e.command(`dev`).description(`Start development server with Vite HMR (zero-downtime reload)`).option(`-e, --entry <file>`,`Entry file`,`src/index.ts`).option(`-p, --port <port>`,`Port number`).option(`--polling`,`Force chokidar to poll for file changes (Docker / WSL / NFS / older kernels)`).action(async e=>{try{await Gr(e.entry,e.port,{polling:e.polling})}catch(e){e.code===`ERR_MODULE_NOT_FOUND`&&e.message?.includes(`vite`)?console.error(`
3677
+ `);let _=async()=>{h&&clearTimeout(h),await d.close(),process.exit(0)};process.on(`SIGINT`,_),process.on(`SIGTERM`,_)}function ni(e){e.command(`dev`).description(`Start development server with Vite HMR (zero-downtime reload)`).option(`-e, --entry <file>`,`Entry file`,`src/index.ts`).option(`-p, --port <port>`,`Port number`).option(`--polling`,`Force chokidar to poll for file changes (Docker / WSL / NFS / older kernels)`).action(async e=>{try{await ti(e.entry,e.port,{polling:e.polling})}catch(e){e.code===`ERR_MODULE_NOT_FOUND`&&e.message?.includes(`vite`)?console.error(`
3663
3678
  Error: vite is not installed.
3664
3679
  Run: pnpm add -D vite unplugin-swc
3665
3680
  `):console.error(`
3666
3681
  Dev server failed:`,e.message??e),process.exit(1)}}),e.command(`build`).description(`Build for production via Vite`).action(async()=>{console.log(`
3667
3682
  Building for production...
3668
- `);let{createRequire:e}=await import(`node:module`),{build:t}=await import(w(e(C(`package.json`)).resolve(`vite`)).href);await t({configFile:C(`vite.config.ts`)});let n=await r(process.cwd()),i=n?.copyDirs??[];if(i.length>0){console.log(`
3669
- Copying directories to dist...`);for(let e of i){let t=typeof e==`string`?e:e.src,n=typeof e==`string`?x(`dist`,e):e.dest??x(`dist`,t),r=C(t),i=C(n);if(!h(r)){console.log(` ⚠ Skipped ${t} (not found)`);continue}g(i,{recursive:!0}),m(r,i,{recursive:!0}),console.log(` ✓ ${t} → ${n}`)}}if(n?.assetMap&&Object.keys(n.assetMap).length>0){console.log(`
3670
- Building asset map...`);try{await zr(n,{cwd:process.cwd()})}catch(e){console.error(` ✗ asset build failed: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}console.log(`
3683
+ `);let{createRequire:e}=await import(`node:module`),{build:t}=await import(T(e(w(`package.json`)).resolve(`vite`)).href);await t({configFile:w(`vite.config.ts`)});let n=await r(process.cwd()),i=n?.copyDirs??[];if(i.length>0){console.log(`
3684
+ Copying directories to dist...`);for(let e of i){let t=typeof e==`string`?e:e.src,n=typeof e==`string`?S(`dist`,e):e.dest??S(`dist`,t),r=w(t),i=w(n);if(!g(r)){console.log(` ⚠ Skipped ${t} (not found)`);continue}_(i,{recursive:!0}),h(r,i,{recursive:!0}),console.log(` ✓ ${t} → ${n}`)}}if(n?.assetMap&&Object.keys(n.assetMap).length>0){console.log(`
3685
+ Building asset map...`);try{await Yr(n,{cwd:process.cwd()})}catch(e){console.error(` ✗ asset build failed: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}console.log(`
3671
3686
  Build complete.
3672
3687
  `)}),e.command(`build:assets`).description(`Rebuild the .kickjs-assets.json manifest under the configured outDir (no JS rebuild)`).action(async()=>{let e=await r(process.cwd());if(!e?.assetMap||Object.keys(e.assetMap).length===0){console.log(` No assetMap entries — nothing to build.`);return}console.log(`
3673
- Building asset map...`);try{await zr(e,{cwd:process.cwd()}),console.log(`
3688
+ Building asset map...`);try{await Yr(e,{cwd:process.cwd()}),console.log(`
3674
3689
  Asset build complete.
3675
- `)}catch(e){console.error(` ✗ ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}),e.command(`start`).description(`Start production server`).option(`-e, --entry <file>`,`Entry file`,`dist/index.js`).option(`-p, --port <port>`,`Port number`).action(e=>{let t={NODE_ENV:`production`};e.port&&(t.PORT=String(e.port)),Me(e.entry,t)}),e.command(`dev:debug`).description(`Start dev server with Node.js inspector attached`).option(`-e, --entry <file>`,`Entry file`,`src/index.ts`).option(`-p, --port <port>`,`Port number`).option(`--inspect-port <port>`,`Inspector port`,`9229`).action(async e=>{let t=e.inspectPort??`9229`;process.env.NODE_OPTIONS=`--inspect=0.0.0.0:${t}`,console.log(` Debugger: ws://0.0.0.0:${t}`);try{await Gr(e.entry,e.port)}catch(e){console.error(`
3676
- Dev server (debug) failed:`,e.message??e),process.exit(1)}})}function qr(e){e.command(`info`).description(`Print system and framework info`).action(()=>{console.log(`
3690
+ `)}catch(e){console.error(` ✗ ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}),e.command(`start`).description(`Start production server`).option(`-e, --entry <file>`,`Entry file`,`dist/index.js`).option(`-p, --port <port>`,`Port number`).action(e=>{let t={NODE_ENV:`production`};e.port&&(t.PORT=String(e.port)),Ne(e.entry,t)}),e.command(`dev:debug`).description(`Start dev server with Node.js inspector attached`).option(`-e, --entry <file>`,`Entry file`,`src/index.ts`).option(`-p, --port <port>`,`Port number`).option(`--inspect-port <port>`,`Inspector port`,`9229`).action(async e=>{let t=e.inspectPort??`9229`;process.env.NODE_OPTIONS=`--inspect=0.0.0.0:${t}`,console.log(` Debugger: ws://0.0.0.0:${t}`);try{await ti(e.entry,e.port)}catch(e){console.error(`
3691
+ Dev server (debug) failed:`,e.message??e),process.exit(1)}})}function ri(e){e.command(`info`).description(`Print system and framework info`).action(()=>{console.log(`
3677
3692
  KickJS CLI
3678
3693
 
3679
3694
  System:
3680
- OS: ${xe()} ${Se()} (${be()})
3695
+ OS: ${Se()} ${Ce()} (${xe()})
3681
3696
  Node: ${process.version}
3682
3697
 
3683
3698
  Packages:
3684
3699
  @forinda/kickjs workspace
3685
3700
  @forinda/kickjs-vite workspace
3686
3701
  @forinda/kickjs-cli workspace
3687
- `)})}const{bold:J,dim:Y,green:Jr,red:Yr,yellow:Xr,blue:Zr}=k;function Qr(e){let t=Math.floor(e/86400),n=Math.floor(e%86400/3600),r=Math.floor(e%3600/60),i=e%60,a=[];return t&&a.push(`${t}d`),n&&a.push(`${n}h`),r&&a.push(`${r}m`),a.push(`${i}s`),a.join(` `)}async function $r(e){let t=await fetch(e,{signal:AbortSignal.timeout(5e3)});if(!t.ok)throw Error(`${t.status} ${t.statusText}`);return t.json()}async function X(e,t){try{return await $r(`${e}${t}`)}catch{return null}}async function ei(e){let[t,n,r,i,a]=await Promise.all([X(e,`/health`),X(e,`/metrics`),X(e,`/routes`),X(e,`/container`),X(e,`/ws`)]);return{health:t,metrics:n,routes:r,container:i,ws:a}}function ti(e,t){let{health:n,metrics:r,routes:i,container:a,ws:o}=t,s=Y(`─`.repeat(60));if(console.log(),console.log(J(` KickJS Inspector`)+Y(` → ${e}`)),console.log(s),n){let e=n.status===`healthy`?Jr(`● healthy`):Yr(`● `+n.status);console.log(` ${J(`Health:`)} ${e}`)}else console.log(` ${J(`Health:`)} ${Yr(`● unreachable`)}`);if(r){let e=((r.errorRate??0)*100).toFixed(1),t=r.errorRate>.1?Yr:r.errorRate>0?Xr:Jr;console.log(` ${J(`Uptime:`)} ${Qr(r.uptimeSeconds)}`),console.log(` ${J(`Requests:`)} ${r.requests}`),console.log(` ${J(`Errors:`)} ${r.serverErrors} server, ${r.clientErrors??0} client ${Y(`(`)}${t(e+`%`)}${Y(`)`)}`)}if(a&&console.log(` ${J(`DI:`)} ${a.count} bindings`),o&&o.enabled&&console.log(` ${J(`WS:`)} ${o.connections??0} connections, ${o.namespaces??0} namespaces`),i?.routes?.length){console.log(),console.log(J(` Routes`)),console.log(s),console.log(` ${Y(`METHOD`)} ${Y(`PATH`.padEnd(36))} ${Y(`CONTROLLER`)}`);for(let e of i.routes){let t=e.path.length>36?e.path.slice(0,33)+`...`:e.path.padEnd(36);console.log(` ${ft(e.method)} ${t} ${Zr(e.controller)}.${Y(e.handler)}`)}}console.log(s),console.log()}function ni(e){e.command(`inspect [url]`).description(`Connect to a running KickJS app and display debug info`).option(`-p, --port <port>`,`Override port`).option(`-w, --watch`,`Poll every 5 seconds`).option(`-j, --json`,`Output raw JSON`).action(async(e,t)=>{let n=e??`http://localhost:3000`;if(t.port)try{let e=new URL(n);e.port=t.port,n=e.origin}catch{n=`http://localhost:${t.port}`}let r=`${n.replace(/\/$/,``)}/_debug`,i=async()=>{try{let e=await ei(r);t.json?console.log(JSON.stringify(e,null,2)):ti(n,e)}catch(e){t.json?console.log(JSON.stringify({error:String(e)})):(console.error(Yr(` ✖ Could not connect to ${n}`)),console.error(Y(` ${e instanceof Error?e.message:String(e)}`))),t.watch||(process.exitCode=1)}};if(t.watch){let e=async()=>{process.stdout.write(`\x1B[2J\x1B[H`),await i()};await e(),setInterval(e,5e3)}else await i()})}function ri(e,t){let n=e.toLowerCase();return t.every(e=>n.includes(e.toLowerCase()))}function Z(e,t){let n=e.toLowerCase();return t.some(e=>n.includes(e.toLowerCase()))}const ii=[{match(e,t){let n=ri(e,[`config`,`get`])&&Z(e,[`undefined`,`null`]),r=e.includes(`@Value`)&&Z(e,[`undefined`,`is not defined`]);return!n&&!r?null:{confidence:n&&r?90:75,diagnosis:{id:`env-schema-not-registered`,title:`ConfigService.get() returns undefined for user-defined keys`,explanation:`Your src/index.ts is missing \`import "./config"\`. That side-effect import
3702
+ `)})}const{bold:Y,dim:X,green:ii,red:ai,yellow:oi,blue:si}=A;function ci(e){let t=Math.floor(e/86400),n=Math.floor(e%86400/3600),r=Math.floor(e%3600/60),i=e%60,a=[];return t&&a.push(`${t}d`),n&&a.push(`${n}h`),r&&a.push(`${r}m`),a.push(`${i}s`),a.join(` `)}async function li(e){let t=await fetch(e,{signal:AbortSignal.timeout(5e3)});if(!t.ok)throw Error(`${t.status} ${t.statusText}`);return t.json()}async function ui(e,t){try{return await li(`${e}${t}`)}catch{return null}}async function di(e){let[t,n,r,i,a]=await Promise.all([ui(e,`/health`),ui(e,`/metrics`),ui(e,`/routes`),ui(e,`/container`),ui(e,`/ws`)]);return{health:t,metrics:n,routes:r,container:i,ws:a}}function fi(e,t){let{health:n,metrics:r,routes:i,container:a,ws:o}=t,s=X(`─`.repeat(60));if(console.log(),console.log(Y(` KickJS Inspector`)+X(` → ${e}`)),console.log(s),n){let e=n.status===`healthy`?ii(`● healthy`):ai(`● `+n.status);console.log(` ${Y(`Health:`)} ${e}`)}else console.log(` ${Y(`Health:`)} ${ai(`● unreachable`)}`);if(r){let e=((r.errorRate??0)*100).toFixed(1),t=r.errorRate>.1?ai:r.errorRate>0?oi:ii;console.log(` ${Y(`Uptime:`)} ${ci(r.uptimeSeconds)}`),console.log(` ${Y(`Requests:`)} ${r.requests}`),console.log(` ${Y(`Errors:`)} ${r.serverErrors} server, ${r.clientErrors??0} client ${X(`(`)}${t(e+`%`)}${X(`)`)}`)}if(a&&console.log(` ${Y(`DI:`)} ${a.count} bindings`),o&&o.enabled&&console.log(` ${Y(`WS:`)} ${o.connections??0} connections, ${o.namespaces??0} namespaces`),i?.routes?.length){console.log(),console.log(Y(` Routes`)),console.log(s),console.log(` ${X(`METHOD`)} ${X(`PATH`.padEnd(36))} ${X(`CONTROLLER`)}`);for(let e of i.routes){let t=e.path.length>36?e.path.slice(0,33)+`...`:e.path.padEnd(36);console.log(` ${gt(e.method)} ${t} ${si(e.controller)}.${X(e.handler)}`)}}console.log(s),console.log()}function pi(e){e.command(`inspect [url]`).description(`Connect to a running KickJS app and display debug info`).option(`-p, --port <port>`,`Override port`).option(`-w, --watch`,`Poll every 5 seconds`).option(`-j, --json`,`Output raw JSON`).action(async(e,t)=>{let n=e??`http://localhost:3000`;if(t.port)try{let e=new URL(n);e.port=t.port,n=e.origin}catch{n=`http://localhost:${t.port}`}let r=`${n.replace(/\/$/,``)}/_debug`,i=async()=>{try{let e=await di(r);t.json?console.log(JSON.stringify(e,null,2)):fi(n,e)}catch(e){t.json?console.log(JSON.stringify({error:String(e)})):(console.error(ai(` ✖ Could not connect to ${n}`)),console.error(X(` ${e instanceof Error?e.message:String(e)}`))),t.watch||(process.exitCode=1)}};if(t.watch){let e=async()=>{process.stdout.write(`\x1B[2J\x1B[H`),await i()};await e(),setInterval(e,5e3)}else await i()})}function mi(e,t){let n=e.toLowerCase();return t.every(e=>n.includes(e.toLowerCase()))}function Z(e,t){let n=e.toLowerCase();return t.some(e=>n.includes(e.toLowerCase()))}const hi=[{match(e,t){let n=mi(e,[`config`,`get`])&&Z(e,[`undefined`,`null`]),r=e.includes(`@Value`)&&Z(e,[`undefined`,`is not defined`]);return!n&&!r?null:{confidence:n&&r?90:75,diagnosis:{id:`env-schema-not-registered`,title:`ConfigService.get() returns undefined for user-defined keys`,explanation:`Your src/index.ts is missing \`import "./config"\`. That side-effect import
3688
3703
  registers the env schema with kickjs at module-load time. Without it,
3689
3704
  ConfigService falls back to the base schema (PORT/NODE_ENV/LOG_LEVEL only)
3690
3705
  and every user-defined key reads as undefined. @Value() may *appear* to
@@ -3706,7 +3721,7 @@ describe('UserController', () => {
3706
3721
  beforeEach(() => Container.reset())
3707
3722
 
3708
3723
  it('does the thing', async () => { /* ... */ })
3709
- })`,docs:`https://forinda.github.io/kick-js/guide/testing.html`}}:null}},{match(e,t){return e.includes(`@Module`)||ri(e,[`Module`,`is not a function`])||ri(e,[`Module`,`no exported member`])?{confidence:80,diagnosis:{id:`module-decorator-not-found`,title:`KickJS does not have a @Module decorator (different pattern from NestJS)`,explanation:`NestJS uses @Module({ controllers, providers }). KickJS uses an interface
3724
+ })`,docs:`https://forinda.github.io/kick-js/guide/testing.html`}}:null}},{match(e,t){return e.includes(`@Module`)||mi(e,[`Module`,`is not a function`])||mi(e,[`Module`,`no exported member`])?{confidence:80,diagnosis:{id:`module-decorator-not-found`,title:`KickJS does not have a @Module decorator (different pattern from NestJS)`,explanation:`NestJS uses @Module({ controllers, providers }). KickJS uses an interface
3710
3725
  pattern instead: a class implements AppModule and exposes routes() that
3711
3726
  returns the controller wiring. This was a deliberate choice — modules
3712
3727
  become explicit values rather than metadata, which makes them easier to
@@ -3758,24 +3773,24 @@ drop the entry.`,fix:`Open src/modules/index.ts and verify the module is in the
3758
3773
  import { UserModule } from './users/user.module'
3759
3774
  import { TaskModule } from './tasks/task.module' // ← was this missing?
3760
3775
 
3761
- export const modules: AppModuleEntry[] = [UserModule(), TaskModule()]`,docs:`https://forinda.github.io/kick-js/guide/project-structure.html`}}:null}}];function ai(e,t){let n=null;for(let r of ii){let i=null;try{i=r.match(e,t)}catch{continue}!i||i.confidence<40||(!n||i.confidence>n.confidence)&&(n=i)}return n}async function oi(e){let t=e.provider??`openai`,n=process.env.OPENAI_API_KEY;if(t===`openai`&&!n)return{kind:`unavailable`,reason:`OPENAI_API_KEY environment variable is not set`,suggestion:`Set OPENAI_API_KEY in your shell, e.g.
3776
+ export const modules: AppModuleEntry[] = [UserModule(), TaskModule()]`,docs:`https://forinda.github.io/kick-js/guide/project-structure.html`}}:null}}];function gi(e,t){let n=null;for(let r of hi){let i=null;try{i=r.match(e,t)}catch{continue}!i||i.confidence<40||(!n||i.confidence>n.confidence)&&(n=i)}return n}async function _i(e){let t=e.provider??`openai`,n=process.env.OPENAI_API_KEY;if(t===`openai`&&!n)return{kind:`unavailable`,reason:`OPENAI_API_KEY environment variable is not set`,suggestion:`Set OPENAI_API_KEY in your shell, e.g.
3762
3777
  export OPENAI_API_KEY="sk-..."
3763
3778
 
3764
3779
  Then re-run \`kick explain --ai "<your error>"\`.`};let r;try{r=await import(`@forinda/kickjs-ai`)}catch{return{kind:`unavailable`,reason:`@forinda/kickjs-ai is not installed`,suggestion:`Install the AI package to enable the LLM fallback:
3765
3780
  kick add ai
3766
3781
 
3767
3782
  Or manually:
3768
- pnpm add @forinda/kickjs-ai`}}let{OpenAIProvider:i}=r,a=new i({apiKey:n,defaultChatModel:e.model??`gpt-4o-mini`}),o=si(e.cwd),s=`Error or stack trace:\n\n${e.input.trim()}`;try{let e=ci((await a.chat({messages:[{role:`system`,content:o},{role:`user`,content:s}]})).content);return e?{kind:`ok`,diagnosis:e}:{kind:`error`,message:`The LLM responded but the payload was not valid JSON in the expected shape. Try again, or file an issue with the error text.`}}catch(e){return{kind:`error`,message:`LLM request failed: ${e instanceof Error?e.message:String(e)}`}}}function si(e){return[`You are a diagnostic assistant for KickJS, a decorator-driven Node.js`,`framework built on Express 5 and TypeScript. KickJS projects use:`,` - @Controller, @Get, @Post, @Autowired, @Service, @Value decorators`,` - An AppModule interface with a routes() method (NOT a @Module decorator)`,` - Zod schemas as both runtime validators and OpenAPI sources`,` - Ctx<KickRoutes.ControllerName['method']> for typed request context`,` - src/config/index.ts with defineEnv/loadEnv for env schema`,' - A side-effect `import "./config"` in src/index.ts to register the schema',` - Container.reset() in beforeEach for DI test isolation`,``,`When the user gives you an error message or stack trace, produce a`,`structured diagnosis that helps them fix the bug. You MUST respond`,`with a single JSON object (no surrounding prose, no markdown fences)`,`matching this shape:`,``,`{`,` "id": "<kebab-case-identifier>",`,` "title": "<one-line problem summary>",`,` "explanation": "<multi-line explanation of what is wrong>",`,` "fix": "<multi-line instructions for fixing the problem>",`,` "codeBefore": "<optional: broken code snippet>",`,` "codeAfter": "<optional: corrected code snippet>",`,` "docs": "<optional: KickJS doc URL that discusses this topic>"`,`}`,``,`The KickJS docs live at https://forinda.github.io/kick-js/ — prefer`,`that domain for any doc links you suggest.`,e?`The project is located at ${e}.`:``].filter(e=>e.length>0).join(`
3769
- `)}function ci(e){let t=[e,li(e),ui(e)].filter(e=>e!==null);for(let e of t)try{let t=JSON.parse(e);if(di(t))return t}catch{continue}return null}function li(e){let t=e.match(/```(?:json)?\s*\n([\s\S]*?)```/);return t?t[1]?.trim()??null:null}function ui(e){let t=e.indexOf(`{`);if(t===-1)return null;let n=0,r=!1,i=!1;for(let a=t;a<e.length;a++){let o=e[a];if(i){i=!1;continue}if(o===`\\`&&r){i=!0;continue}if(o===`"`){r=!r;continue}if(!r&&(o===`{`&&n++,o===`}`&&(n--,n===0)))return e.slice(t,a+1)}return null}function di(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.id==`string`&&typeof t.title==`string`&&typeof t.explanation==`string`&&typeof t.fix==`string`}function fi(e){e.command(`explain [message]`).description(`Explain a KickJS error and suggest a fix`).option(`-m, --message <text>`,`Error message to explain (alternative to positional arg)`).option(`--ai`,`Fall back to LLM if no known-issue matches (requires @forinda/kickjs-ai)`).option(`--model <name>`,`Model name for the --ai fallback`,`gpt-4o-mini`).option(`--json`,`Output the diagnosis as JSON for tooling integration`).action(async(e,t)=>{let n=await hi(e,t.message);(!n||n.trim().length===0)&&(process.stderr.write(`Error: no input provided.
3783
+ pnpm add @forinda/kickjs-ai`}}let{OpenAIProvider:i}=r,a=new i({apiKey:n,defaultChatModel:e.model??`gpt-4o-mini`}),o=vi(e.cwd),s=`Error or stack trace:\n\n${e.input.trim()}`;try{let e=yi((await a.chat({messages:[{role:`system`,content:o},{role:`user`,content:s}]})).content);return e?{kind:`ok`,diagnosis:e}:{kind:`error`,message:`The LLM responded but the payload was not valid JSON in the expected shape. Try again, or file an issue with the error text.`}}catch(e){return{kind:`error`,message:`LLM request failed: ${e instanceof Error?e.message:String(e)}`}}}function vi(e){return[`You are a diagnostic assistant for KickJS, a decorator-driven Node.js`,`framework built on Express 5 and TypeScript. KickJS projects use:`,` - @Controller, @Get, @Post, @Autowired, @Service, @Value decorators`,` - An AppModule interface with a routes() method (NOT a @Module decorator)`,` - Zod schemas as both runtime validators and OpenAPI sources`,` - Ctx<KickRoutes.ControllerName['method']> for typed request context`,` - src/config/index.ts with defineEnv/loadEnv for env schema`,' - A side-effect `import "./config"` in src/index.ts to register the schema',` - Container.reset() in beforeEach for DI test isolation`,``,`When the user gives you an error message or stack trace, produce a`,`structured diagnosis that helps them fix the bug. You MUST respond`,`with a single JSON object (no surrounding prose, no markdown fences)`,`matching this shape:`,``,`{`,` "id": "<kebab-case-identifier>",`,` "title": "<one-line problem summary>",`,` "explanation": "<multi-line explanation of what is wrong>",`,` "fix": "<multi-line instructions for fixing the problem>",`,` "codeBefore": "<optional: broken code snippet>",`,` "codeAfter": "<optional: corrected code snippet>",`,` "docs": "<optional: KickJS doc URL that discusses this topic>"`,`}`,``,`The KickJS docs live at https://forinda.github.io/kick-js/ — prefer`,`that domain for any doc links you suggest.`,e?`The project is located at ${e}.`:``].filter(e=>e.length>0).join(`
3784
+ `)}function yi(e){let t=[e,bi(e),xi(e)].filter(e=>e!==null);for(let e of t)try{let t=JSON.parse(e);if(Si(t))return t}catch{continue}return null}function bi(e){let t=e.match(/```(?:json)?\s*\n([\s\S]*?)```/);return t?t[1]?.trim()??null:null}function xi(e){let t=e.indexOf(`{`);if(t===-1)return null;let n=0,r=!1,i=!1;for(let a=t;a<e.length;a++){let o=e[a];if(i){i=!1;continue}if(o===`\\`&&r){i=!0;continue}if(o===`"`){r=!r;continue}if(!r&&(o===`{`&&n++,o===`}`&&(n--,n===0)))return e.slice(t,a+1)}return null}function Si(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.id==`string`&&typeof t.title==`string`&&typeof t.explanation==`string`&&typeof t.fix==`string`}function Ci(e){e.command(`explain [message]`).description(`Explain a KickJS error and suggest a fix`).option(`-m, --message <text>`,`Error message to explain (alternative to positional arg)`).option(`--ai`,`Fall back to LLM if no known-issue matches (requires @forinda/kickjs-ai)`).option(`--model <name>`,`Model name for the --ai fallback`,`gpt-4o-mini`).option(`--json`,`Output the diagnosis as JSON for tooling integration`).action(async(e,t)=>{let n=await Ei(e,t.message);(!n||n.trim().length===0)&&(process.stderr.write(`Error: no input provided.
3770
3785
 
3771
3786
  Pass a message as a positional arg, --message flag, or pipe via stdin:
3772
3787
  kick explain "config.get returned undefined"
3773
3788
  pnpm test 2>&1 | kick explain
3774
- `),process.exit(1));let r=_i(),i=ai(n,r);if(t.json&&i){process.stdout.write(JSON.stringify({matched:!0,...i},null,2)+`
3775
- `);return}if(i){vi(n,i.diagnosis,i.confidence);return}t.ai||(t.json&&(process.stdout.write(JSON.stringify({matched:!1},null,2)+`
3776
- `),process.exit(2)),yi(n,!1),process.exit(2));let a=await oi({input:n,model:t.model,cwd:r.cwd});t.json&&(process.stdout.write(JSON.stringify(pi(a),null,2)+`
3777
- `),process.exit(a.kind===`ok`?0:2)),mi(n,a),process.exit(a.kind===`ok`?0:2)})}function pi(e){return e.kind===`ok`?{matched:!0,source:`ai`,diagnosis:e.diagnosis}:e.kind===`unavailable`?{matched:!1,aiUnavailable:!0,reason:e.reason}:{matched:!1,aiError:!0,error:e.message}}function mi(e,t){if(t.kind===`ok`){vi(e,t.diagnosis,-1,!0);return}if(t.kind===`unavailable`){process.stdout.write(`\n Explaining: ${xi(e.trim(),200)}\n\n`),process.stdout.write(` AI fallback unavailable: ${t.reason}\n\n`),process.stdout.write(`${bi(t.suggestion,` `)}\n\n`);return}process.stdout.write(`\n Explaining: ${xi(e.trim(),200)}\n\n`),process.stdout.write(` AI fallback error: ${t.message}\n\n`)}async function hi(e,t){return e&&e.trim().length>0?e:t&&t.trim().length>0?t:process.stdin.isTTY?``:gi()}function gi(){return new Promise((e,t)=>{let n=``;process.stdin.setEncoding(`utf8`),process.stdin.on(`data`,e=>{n+=e}),process.stdin.on(`end`,()=>e(n)),process.stdin.on(`error`,t)})}function _i(){let e=process.cwd();return{cwd:e,hasFile:t=>h(C(e,t))}}function vi(e,t,n,r=!1){let i=xi(e.trim(),200),a=r?`AI-generated — verify before applying`:Si(n);process.stdout.write(`\n Explaining: ${i}\n`),process.stdout.write(`\n Match: ${t.id} (${a})\n`),process.stdout.write(` Title: ${t.title}\n`),process.stdout.write(`\n Diagnosis:\n${bi(t.explanation,` `)}\n`),process.stdout.write(`\n Fix:\n${bi(t.fix,` `)}\n`),t.codeBefore&&process.stdout.write(`\n Before:\n${bi(t.codeBefore,` `)}\n`),t.codeAfter&&process.stdout.write(`\n After:\n${bi(t.codeAfter,` `)}\n`),t.docs&&process.stdout.write(`\n Docs: ${t.docs}\n`),process.stdout.write(`
3778
- `)}function yi(e,t){let n=xi(e.trim(),200);process.stdout.write(`\n Explaining: ${n}\n\n`),t?process.stdout.write(` No known-issue matched, and --ai fallback is not yet wired.
3789
+ `),process.exit(1));let r=Oi(),i=gi(n,r);if(t.json&&i){process.stdout.write(JSON.stringify({matched:!0,...i},null,2)+`
3790
+ `);return}if(i){ki(n,i.diagnosis,i.confidence);return}t.ai||(t.json&&(process.stdout.write(JSON.stringify({matched:!1},null,2)+`
3791
+ `),process.exit(2)),Ai(n,!1),process.exit(2));let a=await _i({input:n,model:t.model,cwd:r.cwd});t.json&&(process.stdout.write(JSON.stringify(wi(a),null,2)+`
3792
+ `),process.exit(a.kind===`ok`?0:2)),Ti(n,a),process.exit(a.kind===`ok`?0:2)})}function wi(e){return e.kind===`ok`?{matched:!0,source:`ai`,diagnosis:e.diagnosis}:e.kind===`unavailable`?{matched:!1,aiUnavailable:!0,reason:e.reason}:{matched:!1,aiError:!0,error:e.message}}function Ti(e,t){if(t.kind===`ok`){ki(e,t.diagnosis,-1,!0);return}if(t.kind===`unavailable`){process.stdout.write(`\n Explaining: ${Mi(e.trim(),200)}\n\n`),process.stdout.write(` AI fallback unavailable: ${t.reason}\n\n`),process.stdout.write(`${ji(t.suggestion,` `)}\n\n`);return}process.stdout.write(`\n Explaining: ${Mi(e.trim(),200)}\n\n`),process.stdout.write(` AI fallback error: ${t.message}\n\n`)}async function Ei(e,t){return e&&e.trim().length>0?e:t&&t.trim().length>0?t:process.stdin.isTTY?``:Di()}function Di(){return new Promise((e,t)=>{let n=``;process.stdin.setEncoding(`utf8`),process.stdin.on(`data`,e=>{n+=e}),process.stdin.on(`end`,()=>e(n)),process.stdin.on(`error`,t)})}function Oi(){let e=process.cwd();return{cwd:e,hasFile:t=>g(w(e,t))}}function ki(e,t,n,r=!1){let i=Mi(e.trim(),200),a=r?`AI-generated — verify before applying`:Ni(n);process.stdout.write(`\n Explaining: ${i}\n`),process.stdout.write(`\n Match: ${t.id} (${a})\n`),process.stdout.write(` Title: ${t.title}\n`),process.stdout.write(`\n Diagnosis:\n${ji(t.explanation,` `)}\n`),process.stdout.write(`\n Fix:\n${ji(t.fix,` `)}\n`),t.codeBefore&&process.stdout.write(`\n Before:\n${ji(t.codeBefore,` `)}\n`),t.codeAfter&&process.stdout.write(`\n After:\n${ji(t.codeAfter,` `)}\n`),t.docs&&process.stdout.write(`\n Docs: ${t.docs}\n`),process.stdout.write(`
3793
+ `)}function Ai(e,t){let n=Mi(e.trim(),200);process.stdout.write(`\n Explaining: ${n}\n\n`),t?process.stdout.write(` No known-issue matched, and --ai fallback is not yet wired.
3779
3794
  When @forinda/kickjs-ai ships its provider implementations,
3780
3795
  this command will call the configured LLM with the error +
3781
3796
  project context and return a structured fix.
@@ -3792,12 +3807,12 @@ Pass a message as a positional arg, --message flag, or pipe via stdin:
3792
3807
  3. File an issue with the error text:
3793
3808
  https://github.com/forinda/kick-js/issues/new
3794
3809
 
3795
- `)}function bi(e,t){return e.split(`
3810
+ `)}function ji(e,t){return e.split(`
3796
3811
  `).map(e=>`${t}${e}`).join(`
3797
- `)}function xi(e,t){return e.length<=t?e:e.slice(0,t-1)+`…`}function Si(e){return e>=90?`high confidence`:e>=70?`good match`:e>=50?`medium confidence`:`low confidence — verify manually`}function Ci(e){let t=e.command(`mcp`).description(`Model Context Protocol commands (start | init)`);t.command(`start`,{isDefault:!0}).description(`Run the built application as an MCP server over stdio`).option(`-e, --entry <file>`,`Entry file`,`dist/index.js`).option(`--node-arg <arg...>`,`Extra arguments to pass to node`).action(wi),t.command(`init`).description(`Generate .mcp.json for Claude Code / Cursor / Zed`).option(`-n, --name <name>`,`Server name (defaults to package.json name)`).option(`-o, --out <file>`,`Output file`,`.mcp.json`).option(`-f, --force`,`Overwrite an existing entry without prompting`).option(`--global`,`Write to ~/.mcp.json instead of the project root`).action(Ti)}function wi(e){let t=C(e.entry);h(t)||(process.stderr.write(`Error: entry file not found: ${t}\n\nBuild the app first with \`kick build\`, or pass a custom entry:\n kick mcp -e dist/server.js\n`),process.exit(1));let n=[...e.nodeArg??[],t],r=le(process.execPath,n,{stdio:`inherit`,env:{...process.env,KICK_MCP_STDIO:`1`,NODE_ENV:process.env.NODE_ENV??`production`}});r.on(`error`,e=>{process.stderr.write(`Failed to start MCP server: ${e.message}\n`),process.exit(1)}),r.on(`exit`,(e,t)=>{if(t){process.kill(process.pid,t);return}process.exit(e??0)});let i=e=>{r.killed||r.kill(e)};process.on(`SIGINT`,()=>i(`SIGINT`)),process.on(`SIGTERM`,()=>i(`SIGTERM`))}function Ti(e){let t=process.cwd(),n=Ei(t)??re(t),r=e.name??n,i=e.global?C(process.env.HOME??`.`,`.mcp.json`):C(t,e.out),a={command:`kick`,args:[`mcp`],cwd:t},o={mcpServers:{}};if(h(i))try{let e=_(i,`utf8`),t=JSON.parse(e);t&&typeof t==`object`&&t.mcpServers&&(o={mcpServers:{...t.mcpServers}})}catch(e){let t=e instanceof Error?e.message:String(e);process.stderr.write(`Error: existing ${i} is not valid JSON (${t}).\nFix the file or pass --force to overwrite the entry.\n`),process.exit(1)}o.mcpServers[r]&&!e.force&&(process.stderr.write(`Error: an entry for "${r}" already exists in ${i}.\nPass --force to overwrite it, or use --name to pick a different key.\n`),process.exit(1)),o.mcpServers[r]=a,ne(i,JSON.stringify(o,null,2)+`
3798
- `,`utf8`),process.stdout.write(`\n ✓ Wrote MCP server entry "${r}" to ${i}\n\n To activate it:\n 1. Build your app: kick build\n 2. Restart your MCP client (Claude Code, Cursor, Zed)\n 3. The server should appear in the client's tool picker\n\n`)}function Ei(e){let t=C(e,`package.json`);if(!h(t))return null;try{let e=_(t,`utf8`),n=JSON.parse(e);return typeof n.name==`string`?n.name:null}catch{return null}}function Di(e){e.command(`tinker`).description(`Interactive REPL with DI container and services loaded`).option(`-e, --entry <file>`,`Entry file to load`,`src/index.ts`).action(async e=>{let t=process.cwd(),n=C(t,e.entry);h(n)||(console.error(`\n Error: ${e.entry} not found.\n`),process.exit(1));let r=ki(t,`tsx`);r||(console.error(`
3812
+ `)}function Mi(e,t){return e.length<=t?e:e.slice(0,t-1)+`…`}function Ni(e){return e>=90?`high confidence`:e>=70?`good match`:e>=50?`medium confidence`:`low confidence — verify manually`}function Pi(e){let t=e.command(`mcp`).description(`Model Context Protocol commands (start | init)`);t.command(`start`,{isDefault:!0}).description(`Run the built application as an MCP server over stdio`).option(`-e, --entry <file>`,`Entry file`,`dist/index.js`).option(`--node-arg <arg...>`,`Extra arguments to pass to node`).action(Fi),t.command(`init`).description(`Generate .mcp.json for Claude Code / Cursor / Zed`).option(`-n, --name <name>`,`Server name (defaults to package.json name)`).option(`-o, --out <file>`,`Output file`,`.mcp.json`).option(`-f, --force`,`Overwrite an existing entry without prompting`).option(`--global`,`Write to ~/.mcp.json instead of the project root`).action(Ii)}function Fi(e){let t=w(e.entry);g(t)||(process.stderr.write(`Error: entry file not found: ${t}\n\nBuild the app first with \`kick build\`, or pass a custom entry:\n kick mcp -e dist/server.js\n`),process.exit(1));let n=[...e.nodeArg??[],t],r=ue(process.execPath,n,{stdio:`inherit`,env:{...process.env,KICK_MCP_STDIO:`1`,NODE_ENV:process.env.NODE_ENV??`production`}});r.on(`error`,e=>{process.stderr.write(`Failed to start MCP server: ${e.message}\n`),process.exit(1)}),r.on(`exit`,(e,t)=>{if(t){process.kill(process.pid,t);return}process.exit(e??0)});let i=e=>{r.killed||r.kill(e)};process.on(`SIGINT`,()=>i(`SIGINT`)),process.on(`SIGTERM`,()=>i(`SIGTERM`))}function Ii(e){let t=process.cwd(),n=Li(t)??re(t),r=e.name??n,i=e.global?w(process.env.HOME??`.`,`.mcp.json`):w(t,e.out),a={command:`kick`,args:[`mcp`],cwd:t},o={mcpServers:{}};if(g(i))try{let e=v(i,`utf8`),t=JSON.parse(e);t&&typeof t==`object`&&t.mcpServers&&(o={mcpServers:{...t.mcpServers}})}catch(e){let t=e instanceof Error?e.message:String(e);process.stderr.write(`Error: existing ${i} is not valid JSON (${t}).\nFix the file or pass --force to overwrite the entry.\n`),process.exit(1)}o.mcpServers[r]&&!e.force&&(process.stderr.write(`Error: an entry for "${r}" already exists in ${i}.\nPass --force to overwrite it, or use --name to pick a different key.\n`),process.exit(1)),o.mcpServers[r]=a,ne(i,JSON.stringify(o,null,2)+`
3813
+ `,`utf8`),process.stdout.write(`\n ✓ Wrote MCP server entry "${r}" to ${i}\n\n To activate it:\n 1. Build your app: kick build\n 2. Restart your MCP client (Claude Code, Cursor, Zed)\n 3. The server should appear in the client's tool picker\n\n`)}function Li(e){let t=w(e,`package.json`);if(!g(t))return null;try{let e=v(t,`utf8`),n=JSON.parse(e);return typeof n.name==`string`?n.name:null}catch{return null}}function Ri(e){e.command(`tinker`).description(`Interactive REPL with DI container and services loaded`).option(`-e, --entry <file>`,`Entry file to load`,`src/index.ts`).action(async e=>{let t=process.cwd(),n=w(t,e.entry);g(n)||(console.error(`\n Error: ${e.entry} not found.\n`),process.exit(1));let r=Bi(t,`tsx`);r||(console.error(`
3799
3814
  Error: tsx not found. Install it: pnpm add -D tsx
3800
- `),process.exit(1));let i=Oi(n,e.entry),a=x(t,`.kick-tinker.mjs`),{writeFileSync:o,unlinkSync:s}=await import(`node:fs`);o(a,i,`utf-8`);try{let e=ce(a,[],{cwd:t,execPath:r,stdio:`inherit`});await new Promise(t=>{e.on(`exit`,()=>t())})}finally{try{s(a)}catch{}}})}function Oi(e,t){return`
3815
+ `),process.exit(1));let i=zi(n,e.entry),a=S(t,`.kick-tinker.mjs`),{writeFileSync:o,unlinkSync:s}=await import(`node:fs`);o(a,i,`utf-8`);try{let e=le(a,[],{cwd:t,execPath:r,stdio:`inherit`});await new Promise(t=>{e.on(`exit`,()=>t())})}finally{try{s(a)}catch{}}})}function zi(e,t){return`
3801
3816
  import 'reflect-metadata'
3802
3817
 
3803
3818
  // Prevent bootstrap() from starting the HTTP server
@@ -3822,7 +3837,7 @@ try {
3822
3837
 
3823
3838
  // Load entry to trigger decorator registration
3824
3839
  try {
3825
- await import('${w(e).href}')
3840
+ await import('${T(e).href}')
3826
3841
  } catch (err) {
3827
3842
  console.warn(' Warning: ' + err.message)
3828
3843
  console.warn(' Container may be partially initialized.\\n')
@@ -3851,30 +3866,32 @@ server.on('exit', () => {
3851
3866
  console.log('\\n Goodbye!\\n')
3852
3867
  process.exit(0)
3853
3868
  })
3854
- `}function ki(e,t){let n=e;for(;;){let e=x(n,`node_modules`,`.bin`,t);if(h(e))return e;let r=C(n,`..`);if(r===n)break;n=r}return null}async function Ai(e){let{name:t,modulesDir:n,force:r}=e,i=e.pluralize!==!1,a=B(t),o=R(t),s=i?V(a):a,c=x(n,s);if(!await Re(c)){console.log(`\n Module not found: ${c}\n`);return}if(!r&&!await F({message:k.red(`Delete module '${s}' at ${c}? This cannot be undone.`),initialValue:!1})){console.log(`
3869
+ `}function Bi(e,t){let n=e;for(;;){let e=S(n,`node_modules`,`.bin`,t);if(g(e))return e;let r=w(n,`..`);if(r===n)break;n=r}return null}function Vi(e,t){let n=RegExp(`^\\s*${H(t)}Module\\b`),r=!1,i=0,a=e;for(;;){let e=a.indexOf(`.mount(`,i);if(e===-1)break;let t=e+7,o=1,s=t;for(;s<a.length&&o>0;){let e=a.slice(s,s+2);if(e===`//`||e===`/*`){if(e===`//`)for(s+=2;s<a.length&&a[s]!==`
3870
+ `;)s++;else{for(s+=2;s+1<a.length&&!(a[s]===`*`&&a[s+1]===`/`);)s++;s+=2}continue}let t=a[s]??``;if(t===`'`||t===`"`||t==="`"){let e=t;for(s++;s<a.length&&a[s]!==e;)a[s]===`\\`&&s++,s++}else if(t===`(`)o++;else if(t===`)`&&(o--,o===0))break;s++}if(o!==0)break;let c=a.slice(t,s);if(n.test(c)){let t=e;for(;t>0&&(a[t-1]===` `||a[t-1]===` `||a[t-1]===`
3871
+ `);)t--;a=a.slice(0,t)+a.slice(s+1),r=!0,i=t;continue}i=s+1}return{content:a,changed:r}}function Hi(e,t){let n=Ln(e);if(!n)return e;let r=n.rhsStart,i=n.rhsEnd+1,a=e.slice(r,i);return a=Vi(a,t).content,a=a.replace(RegExp(`\\s*,?\\s*${H(t)}Module\\b(?:\\s*\\(\\s*\\))?\\s*,?`,`g`),e=>{let t=e.trimStart().startsWith(`,`),n=e.trimEnd().endsWith(`,`);return t&&n?`,`:``}),a=a.replace(/,(\s*])/,`$1`),e.slice(0,r)+a+e.slice(i)}async function Ui(e){let{name:t,modulesDir:n,force:r}=e,i=e.pluralize!==!1,a=B(t),o=R(t),s=i?V(a):a,c=S(n,s);if(!await ze(c)){console.log(`\n Module not found: ${c}\n`);return}if(!r&&!await F({message:A.red(`Delete module '${s}' at ${c}? This cannot be undone.`),initialValue:!1})){console.log(`
3855
3872
  Cancelled.
3856
- `);return}await he(c,{recursive:!0,force:!0}),console.log(` Deleted: ${c}`);let l=x(n,`index.ts`);if(await Re(l)){let e=await E(l,`utf-8`),t=e,n=RegExp(`^import\\s*\\{\\s*${o}Module\\s*\\}\\s*from\\s*['"][^'"]*${s}(?:/[^'"]*)?['"].*\\n?`,`gm`);e=e.replace(n,``),e=e.replace(RegExp(`\\s*,?\\s*${o}Module(?:\\s*\\(\\s*\\))?\\s*,?`,`g`),e=>{let t=e.trimStart().startsWith(`,`),n=e.trimEnd().endsWith(`,`);return t&&n?`,`:``}),e=e.replace(/,(\s*])/,`$1`),e=e.replace(/\n{3,}/g,`
3873
+ `);return}await ge(c,{recursive:!0,force:!0}),console.log(` Deleted: ${c}`);let l=S(n,`index.ts`);if(await ze(l)){let e=await D(l,`utf-8`),t=e,n=RegExp(`^import\\s*\\{\\s*${H(o)}Module\\s*\\}\\s*from\\s*['"][^'"]*${H(s)}(?:/[^'"]*)?['"].*\\n?`,`gm`);e=e.replace(n,``),e=Hi(e,o),e=e.replace(/\n{3,}/g,`
3857
3874
 
3858
- `),e!==t&&(await D(l,e,`utf-8`),console.log(` Unregistered: ${o}Module from ${l}`))}console.log(`\n Module '${s}' removed.\n`)}function ji(e){e.command(`remove`).alias(`rm`).description(`Remove generated code`).command(`module <names...>`).description(`Remove one or more modules (e.g. kick rm module user task)`).option(`--modules-dir <dir>`,`Modules directory`).option(`--no-pluralize`,`Use singular module name`).option(`-f, --force`,`Skip confirmation prompt`).action(async(e,t)=>{let i=n(await r(process.cwd())),a=t.modulesDir??i.dir??`src/modules`,o=t.pluralize===!1?!1:i.pluralize??!0;for(let n of e)await Ai({name:n,modulesDir:C(a),force:t.force,pluralize:o})})}function Mi(e){if(e!==void 0){if(e===`false`||e===`off`||e===`none`)return!1;if(e===`zod`)return`zod`;console.warn(` kick typegen: unknown --schema-validator '${e}' (only 'zod' and 'false' are supported). Falling back to project config.`)}}function Ni(e){if(e!==void 0)return e===`false`||e===`off`||e===`none`?!1:e}function Pi(e){e.command(`typegen`).description(`Generate type-safe DI registry and module types into .kickjs/types/`).option(`-w, --watch`,`Watch source files and regenerate on change`).option(`-s, --src <dir>`,`Source directory to scan`,`src`).option(`-o, --out <dir>`,`Output directory`,`.kickjs/types`).option(`--silent`,`Suppress output`).option(`--allow-duplicates`,`Auto-namespace duplicate class names instead of failing (use with caution)`).option(`--schema-validator <name>`,`Schema validator for body/query/params typing (currently 'zod' or 'false')`).option(`--env-file <path>`,`Path to env schema file for KickEnv typing (default 'src/env.ts'; pass 'false' to disable)`).option(`--check`,`CI gate: fail on plugin-typegen drift instead of writing`).option(`--list`,"List every registered typegen plugin id (use to populate `typegen.disable`)").action(async e=>{let t=process.cwd(),n=await r(t);if(e.list){let{mergeCliPlugins:e}=await import(`./plugin-D0C4ISZA.mjs`).then(e=>e.t),{builtinCliPlugins:t}=await Promise.resolve().then(()=>ga),r=e([...t,...n?.plugins??[]],n?.commands??[]),i=new Set(n?.typegen?.disable??[]);if(r.typegens.length===0){console.log(` No typegen plugins registered.`);return}let a=Math.max(...r.typegens.map(e=>e.id.length));console.log(`
3875
+ `),e!==t&&(await O(l,e,`utf-8`),console.log(` Unregistered: ${o}Module from ${l}`))}console.log(`\n Module '${s}' removed.\n`)}function Wi(e){e.command(`remove`).alias(`rm`).description(`Remove generated code`).command(`module <names...>`).description(`Remove one or more modules (e.g. kick rm module user task)`).option(`--modules-dir <dir>`,`Modules directory`).option(`--no-pluralize`,`Use singular module name`).option(`-f, --force`,`Skip confirmation prompt`).action(async(e,t)=>{let i=n(await r(process.cwd())),a=t.modulesDir??i.dir??`src/modules`,o=t.pluralize===!1?!1:i.pluralize??!0;for(let n of e)await Ui({name:n,modulesDir:w(a),force:t.force,pluralize:o})})}function Gi(e){if(e!==void 0){if(e===`false`||e===`off`||e===`none`)return!1;if(e===`zod`)return`zod`;console.warn(` kick typegen: unknown --schema-validator '${e}' (only 'zod' and 'false' are supported). Falling back to project config.`)}}function Ki(e){if(e!==void 0)return e===`false`||e===`off`||e===`none`?!1:e}function qi(e){e.command(`typegen`).description(`Generate type-safe DI registry and module types into .kickjs/types/`).option(`-w, --watch`,`Watch source files and regenerate on change`).option(`-s, --src <dir>`,`Source directory to scan`,`src`).option(`-o, --out <dir>`,`Output directory`,`.kickjs/types`).option(`--silent`,`Suppress output`).option(`--allow-duplicates`,`Auto-namespace duplicate class names instead of failing (use with caution)`).option(`--schema-validator <name>`,`Schema validator for body/query/params typing (currently 'zod' or 'false')`).option(`--env-file <path>`,`Path to env schema file for KickEnv typing (default 'src/env.ts'; pass 'false' to disable)`).option(`--check`,`CI gate: fail on plugin-typegen drift instead of writing`).option(`--list`,"List every registered typegen plugin id (use to populate `typegen.disable`)").action(async e=>{let t=process.cwd(),n=await r(t);if(e.list){let{mergeCliPlugins:e}=await import(`./plugin-Dz0Yu4Ow.mjs`).then(e=>e.t),{builtinCliPlugins:t}=await Promise.resolve().then(()=>ka),r=e([...t,...n?.plugins??[]],n?.commands??[]),i=new Set(n?.typegen?.disable??[]);if(r.typegens.length===0){console.log(` No typegen plugins registered.`);return}let a=Math.max(...r.typegens.map(e=>e.id.length));console.log(`
3859
3876
  Registered typegen plugins:
3860
- `);for(let e of r.typegens){let t=i.has(e.id)?` (disabled)`:``;console.log(` ${e.id.padEnd(a+2)}inputs: ${e.inputs.join(`, `)||`(none)`}${t}`)}console.log();return}let i=Mi(e.schemaValidator)??n?.typegen?.schemaValidator??`zod`,a=Ni(e.envFile)??n?.typegen?.envFile,o={cwd:t,srcDir:e.src??n?.typegen?.srcDir,outDir:e.out??n?.typegen?.outDir,silent:e.silent,allowDuplicates:e.allowDuplicates,schemaValidator:i,envFile:a,assetMap:n?.assetMap,runPlugins:!1};try{if(e.watch){let t=await u(o);e.silent||console.log(` kick typegen: watching for changes (Ctrl-C to exit)`);let n=()=>{t(),process.exit(0)};process.on(`SIGINT`,n),process.on(`SIGTERM`,n),await new Promise(()=>{})}else{await f(o);let r=await Rr({cwd:t,config:n??null,silent:e.silent,check:e.check});e.check&&r.some(e=>e.status===`written`)&&process.exit(1)}}catch(e){e instanceof c?console.error(`
3877
+ `);for(let e of r.typegens){let t=i.has(e.id)?` (disabled)`:``;console.log(` ${e.id.padEnd(a+2)}inputs: ${e.inputs.join(`, `)||`(none)`}${t}`)}console.log();return}let i=Gi(e.schemaValidator)??n?.typegen?.schemaValidator??`zod`,a=Ki(e.envFile)??n?.typegen?.envFile,o={cwd:t,srcDir:e.src??n?.typegen?.srcDir,outDir:e.out??n?.typegen?.outDir,silent:e.silent,allowDuplicates:e.allowDuplicates,schemaValidator:i,envFile:a,assetMap:n?.assetMap,runPlugins:!1};try{if(e.watch){let t=await l(o);e.silent||console.log(` kick typegen: watching for changes (Ctrl-C to exit)`);let n=()=>{t(),process.exit(0)};process.on(`SIGINT`,n),process.on(`SIGTERM`,n),await new Promise(()=>{})}else{let{result:r}=await p(o),i=await Jr({cwd:t,config:n??null,silent:e.silent,check:e.check});e.check&&i.some(e=>e.status===`written`)&&process.exit(1),e.check||await u(w(t,e.out??n?.typegen?.outDir??`.kickjs/types`),r.written,i,e.silent??!1)}}catch(e){e instanceof f?console.error(`
3861
3878
  `+e.message+`
3862
- `):e instanceof Error?console.error(`\n kick typegen failed: ${e.message}`):console.error(`\n kick typegen failed: ${JSON.stringify(e)}`),process.exit(1)}})}function Fi(e){let t=[];if(!h(e))return t;let n=ee(e,{withFileTypes:!0});for(let r of n){let n=x(e,r.name);if(r.isDirectory()){if([`node_modules`,`dist`,`.kickjs`,`.git`].includes(r.name))continue;t.push(...Fi(n))}else r.isFile()&&/\.tsx?$/.test(r.name)&&!r.name.endsWith(`.d.ts`)&&t.push(n)}return t}function Ii(e){try{return _(e,`utf-8`)}catch{return``}}const Li=new Set([`secret`,`changeme`,`password`,`test`,`default`,``]);function Ri(e,t){let n=Ii(x(e,`.env`));if(n){let e=n.match(/^JWT_SECRET\s*=\s*['"]?([^'"\n]*)['"]?/m);if(e){let t=e[1].trim();if(Li.has(t.toLowerCase())||t.length<32)return{severity:`CRITICAL`,message:`JWT_SECRET appears to be a default value or too short (< 32 chars) — change it`}}}for(let e of t)for(let t of[/JWT_SECRET['"]?\s*[:=]\s*['"]?(secret|changeme|password|test|default)['"]?/i,/secret\s*[:=]\s*['"]?(secret|changeme|password|test|default)['"]?/i])if(t.test(e))return{severity:`CRITICAL`,message:`JWT_SECRET appears to be a default value in source code — use an environment variable`};return null}function zi(e){for(let t of e)if(/cors\s*\(/.test(t)&&/origin\s*:\s*['"]\*['"]/.test(t))return{severity:`CRITICAL`,message:`CORS origin is '*' — restrict to your domains`};return null}function Bi(e){for(let t of e)if(/rateLimit/i.test(t)||/@RateLimit/i.test(t))return null;return{severity:`WARNING`,message:`No rate limiting detected — add rateLimit() middleware or @RateLimit decorator`}}function Vi(){return process.env.NODE_ENV===`production`?null:{severity:`WARNING`,message:`NODE_ENV is '${process.env.NODE_ENV??`undefined`}', not 'production'`}}function Hi(e){let t=!1,n=!1;for(let r of e)/tokenStore/i.test(r)&&(t=!0),/MemoryTokenStore/i.test(r)&&(n=!0);return n?{severity:`WARNING`,message:`MemoryTokenStore detected — use a persistent store (Redis, DB) for production deployments`}:t?null:{severity:`WARNING`,message:`No token revocation store detected — consider adding one for auth token management`}}function Ui(e){for(let t of e)if(/helmet\s*\(/.test(t))return/security\s*\.\s*helmet\s*.*false/.test(t)?{severity:`WARNING`,message:`Helmet security headers are disabled — enable them for production`}:{severity:`INFO`,message:`Helmet security headers active`};return{severity:`WARNING`,message:`Helmet not detected — add helmet() middleware for security headers`}}function Wi(e){for(let t of e)if(/AuthAdapter/i.test(t))return{severity:`INFO`,message:`AuthAdapter configured`};return{severity:`INFO`,message:`No AuthAdapter detected — add one if your app requires authentication`}}function Gi(e){let t=Fi(x(e,`src`)).map(e=>Ii(e)),n=[],r=Ri(e,t);r&&n.push(r);let i=zi(t);i&&n.push(i);let a=Bi(t);a&&n.push(a);let o=Vi();o&&n.push(o);let s=Hi(t);return s&&n.push(s),n.push(Ui(t)),n.push(Wi(t)),n}function Ki(e){e.command(`check`).description(`Audit project for common issues`).option(`--deploy`,`Run production readiness checks`).action(e=>{if(!e.deploy){console.log(`
3879
+ `):e instanceof Error?console.error(`\n kick typegen failed: ${e.message}`):console.error(`\n kick typegen failed: ${JSON.stringify(e)}`),process.exit(1)}})}function Ji(e){let t=[];if(!g(e))return t;let n=y(e,{withFileTypes:!0});for(let r of n){let n=S(e,r.name);if(r.isDirectory()){if([`node_modules`,`dist`,`.kickjs`,`.git`].includes(r.name))continue;t.push(...Ji(n))}else r.isFile()&&/\.tsx?$/.test(r.name)&&!r.name.endsWith(`.d.ts`)&&t.push(n)}return t}function Yi(e){try{return v(e,`utf-8`)}catch{return``}}const Xi=new Set([`secret`,`changeme`,`password`,`test`,`default`,``]);function Zi(e,t){let n=Yi(S(e,`.env`));if(n){let e=n.match(/^JWT_SECRET\s*=\s*['"]?([^'"\n]*)['"]?/m);if(e){let t=e[1].trim();if(Xi.has(t.toLowerCase())||t.length<32)return{severity:`CRITICAL`,message:`JWT_SECRET appears to be a default value or too short (< 32 chars) — change it`}}}for(let e of t)for(let t of[/JWT_SECRET['"]?\s*[:=]\s*['"]?(secret|changeme|password|test|default)['"]?/i,/secret\s*[:=]\s*['"]?(secret|changeme|password|test|default)['"]?/i])if(t.test(e))return{severity:`CRITICAL`,message:`JWT_SECRET appears to be a default value in source code — use an environment variable`};return null}function Qi(e){for(let t of e)if(/cors\s*\(/.test(t)&&/origin\s*:\s*['"]\*['"]/.test(t))return{severity:`CRITICAL`,message:`CORS origin is '*' — restrict to your domains`};return null}function $i(e){for(let t of e)if(/rateLimit/i.test(t)||/@RateLimit/i.test(t))return null;return{severity:`WARNING`,message:`No rate limiting detected — add rateLimit() middleware or @RateLimit decorator`}}function ea(){return process.env.NODE_ENV===`production`?null:{severity:`WARNING`,message:`NODE_ENV is '${process.env.NODE_ENV??`undefined`}', not 'production'`}}function ta(e){let t=!1,n=!1;for(let r of e)/tokenStore/i.test(r)&&(t=!0),/MemoryTokenStore/i.test(r)&&(n=!0);return n?{severity:`WARNING`,message:`MemoryTokenStore detected — use a persistent store (Redis, DB) for production deployments`}:t?null:{severity:`WARNING`,message:`No token revocation store detected — consider adding one for auth token management`}}function na(e){for(let t of e)if(/helmet\s*\(/.test(t))return/security\s*\.\s*helmet\s*.*false/.test(t)?{severity:`WARNING`,message:`Helmet security headers are disabled — enable them for production`}:{severity:`INFO`,message:`Helmet security headers active`};return{severity:`WARNING`,message:`Helmet not detected — add helmet() middleware for security headers`}}function ra(e){for(let t of e)if(/AuthAdapter/i.test(t))return{severity:`INFO`,message:`AuthAdapter configured`};return{severity:`INFO`,message:`No AuthAdapter detected — add one if your app requires authentication`}}function ia(e){let t=Ji(S(e,`src`)).map(e=>Yi(e)),n=[],r=Zi(e,t);r&&n.push(r);let i=Qi(t);i&&n.push(i);let a=$i(t);a&&n.push(a);let o=ea();o&&n.push(o);let s=ta(t);return s&&n.push(s),n.push(na(t)),n.push(ra(t)),n}function aa(e){e.command(`check`).description(`Audit project for common issues`).option(`--deploy`,`Run production readiness checks`).action(e=>{if(!e.deploy){console.log(`
3863
3880
  Usage: kick check --deploy
3864
3881
 
3865
3882
  Available checks:
3866
3883
  --deploy Audit for production readiness (security, config, best practices)
3867
- `);return}let t=process.cwd();mt(`KickJS Deploy Check`);let n=yt();n.start(`Scanning project...`);let r=Gi(t);n.stop(`Scan complete`);let i={CRITICAL:0,WARNING:1,INFO:2};r.sort((e,t)=>i[e.severity]-i[t.severity]);for(let e of r)I.message(`${pt(e.severity)} ${e.message}`);let a=r.filter(e=>e.severity===`CRITICAL`).length,o=r.filter(e=>e.severity===`WARNING`).length,s=r.filter(e=>e.severity===`INFO`).length,c=o===1?`warning`:`warnings`,l=[a>0?k.red(`${a} critical`):`${a} critical`,o>0?k.yellow(`${o} ${c}`):`${o} ${c}`,`${s} info`].join(`, `);a>0?(P(k.red(`${l} — fix critical issues before deploying`)),process.exit(1)):P(k.green(`${l} — looking good!`))})}async function Q(e){return Ae({configPath:y.resolve(process.cwd(),e.config)})}async function $(e){if(e.adapter){let t=await e.adapter();return{adapter:t,cleanup:async()=>t.close()}}if(!e.connectionString)throw Error(`kickjs-db: no adapter resolved — set db.connectionString (or DATABASE_URL) in kick.config.ts, or supply db.adapter() factory`);let t=e.dialect??`postgres`;if(t!==`postgres`)throw Error(`kickjs-db: built-in CLI adapter only supports postgres in M1 (dialect=${t}); use db.adapter() factory for other dialects`);let[{pgAdapter:n},r]=await Promise.all([import(`@forinda/kickjs-db-pg`),import(`pg`)]),i=new r.default.Pool({connectionString:e.connectionString}),a=n({pool:i});return{adapter:a,cleanup:async()=>{await a.close(),await i.end()}}}function qi(e){if(e.length===0){console.log(`No migrations.`);return}console.table(e.map(e=>({id:e.id,state:e.state,batch:e.batch??`-`,reviewed:e.reviewed,applied:e.appliedAt??`-`})))}function Ji(e){let t=e.command(`db`).description(`Database commands (kickjs-db)`);t.command(`generate <name>`).description(`Generate a new migration from schema diff`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`-e, --empty`,`Skip schema diff and create an empty migration shell (data migration, seed, freeform SQL)`).action(async(e,t)=>{let n=process.cwd(),r=await Ce({name:e,config:await Q(t),cwd:n,empty:t.empty});if(r.status===`no-changes`){console.log(`No schema changes detected.`);return}if(r.empty){console.log(`Created empty migration ${r.migrationDir} (author up.sql + down.sql).`);return}let i=r.changeCount===1?``:`s`;console.log(`Created migration ${r.migrationDir} (${r.changeCount} change${i}).`)});let n=t.command(`migrate`).description(`Migration runner subcommands`);n.command(`latest`).description(`Apply all pending migrations in a new batch`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`--confirm-enum-drop`,"Allow migrations carrying the `-- KICK ENUM REMOVE` header to apply",!1).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let r=await Te({adapter:n,migrationsDir:t.migrationsDir,confirmEnumDrop:e.confirmEnumDrop});r.applied.length===0?console.log(`No pending migrations.`):console.log(`Applied batch ${r.batch}: ${r.applied.join(`, `)}`)}finally{await r()}}),n.command(`up`).description(`Apply the next single pending migration`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`--confirm-enum-drop`,"Allow migrations carrying the `-- KICK ENUM REMOVE` header to apply",!1).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let r=await Oe({adapter:n,migrationsDir:t.migrationsDir,confirmEnumDrop:e.confirmEnumDrop});r.applied.length===0?console.log(`No pending migrations.`):console.log(`Applied ${r.applied[0]} (batch ${r.batch})`)}finally{await r()}}),n.command(`down`).description(`Reverse the most recent applied migration`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let e=await we({adapter:n,migrationsDir:t.migrationsDir});e.reversed?console.log(`Reversed ${e.reversed}.`):console.log(`Nothing to reverse.`)}finally{await r()}}),n.command(`rollback`).description(`Reverse the entire last batch as a single unit`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let e=await Ee({adapter:n,migrationsDir:t.migrationsDir});e.reversed.length===0?console.log(`Nothing to roll back.`):console.log(`Rolled back batch ${e.batch}: ${e.reversed.join(`, `)}`)}finally{await r()}}),n.command(`status`).description(`Print applied + pending migrations`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{qi(await De({adapter:n,migrationsDir:t.migrationsDir}))}finally{await r()}}),t.command(`introspect`).description(`Generate a TypeScript schema file from a live database`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`--out <path>`,`Output file (defaults to db.schemaPath from config)`).option(`--json`,`Print the raw SchemaSnapshot JSON to stdout instead of writing TS source`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let r=await n.introspect();if(e.json){console.log(JSON.stringify(r,null,2));return}let i=e.out??t.schemaPath;await D(i,ke(r),`utf8`);let a=Object.keys(r.tables).length;console.log(`Wrote ${i} (${a} table${a===1?``:`s`}).`)}finally{await r()}})}function Yi(e){return e.optsWithGlobals().dryRun??!1}function Xi(e){e.command(`codemod`).description(`Codebase migration commands (AST-style rewrites — distinct from db migrate)`).command(`modules`).description(`Rewrite module declarations between class form and the defineModule factory.
3884
+ `);return}let t=process.cwd();vt(`KickJS Deploy Check`);let n=wt();n.start(`Scanning project...`);let r=ia(t);n.stop(`Scan complete`);let i={CRITICAL:0,WARNING:1,INFO:2};r.sort((e,t)=>i[e.severity]-i[t.severity]);for(let e of r)I.message(`${_t(e.severity)} ${e.message}`);let a=r.filter(e=>e.severity===`CRITICAL`).length,o=r.filter(e=>e.severity===`WARNING`).length,s=r.filter(e=>e.severity===`INFO`).length,c=o===1?`warning`:`warnings`,l=[a>0?A.red(`${a} critical`):`${a} critical`,o>0?A.yellow(`${o} ${c}`):`${o} ${c}`,`${s} info`].join(`, `);a>0?(yt(A.red(`${l} — fix critical issues before deploying`)),process.exit(1)):yt(A.green(`${l} — looking good!`))})}async function Q(e){return je({configPath:b.resolve(process.cwd(),e.config)})}async function $(e){if(e.adapter){let t=await e.adapter();return{adapter:t,cleanup:async()=>t.close()}}if(!e.connectionString)throw Error(`kickjs-db: no adapter resolved — set db.connectionString (or DATABASE_URL) in kick.config.ts, or supply db.adapter() factory`);let t=e.dialect??`postgres`;if(t!==`postgres`)throw Error(`kickjs-db: built-in CLI adapter only supports postgres in M1 (dialect=${t}); use db.adapter() factory for other dialects`);let[{pgAdapter:n},r]=await Promise.all([import(`@forinda/kickjs-db-pg`),import(`pg`)]),i=new r.default.Pool({connectionString:e.connectionString}),a=n({pool:i});return{adapter:a,cleanup:async()=>{await a.close(),await i.end()}}}function oa(e){if(e.length===0){console.log(`No migrations.`);return}console.table(e.map(e=>({id:e.id,state:e.state,batch:e.batch??`-`,reviewed:e.reviewed,applied:e.appliedAt??`-`})))}function sa(e){let t=e.command(`db`).description(`Database commands (kickjs-db)`);t.command(`generate <name>`).description(`Generate a new migration from schema diff`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`-e, --empty`,`Skip schema diff and create an empty migration shell (data migration, seed, freeform SQL)`).action(async(e,t)=>{let n=process.cwd(),r=await we({name:e,config:await Q(t),cwd:n,empty:t.empty});if(r.status===`no-changes`){console.log(`No schema changes detected.`);return}if(r.empty){console.log(`Created empty migration ${r.migrationDir} (author up.sql + down.sql).`);return}let i=r.changeCount===1?``:`s`;console.log(`Created migration ${r.migrationDir} (${r.changeCount} change${i}).`)});let n=t.command(`migrate`).description(`Migration runner subcommands`);n.command(`latest`).description(`Apply all pending migrations in a new batch`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`--confirm-enum-drop`,"Allow migrations carrying the `-- KICK ENUM REMOVE` header to apply",!1).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let r=await Ee({adapter:n,migrationsDir:t.migrationsDir,confirmEnumDrop:e.confirmEnumDrop});r.applied.length===0?console.log(`No pending migrations.`):console.log(`Applied batch ${r.batch}: ${r.applied.join(`, `)}`)}finally{await r()}}),n.command(`up`).description(`Apply the next single pending migration`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`--confirm-enum-drop`,"Allow migrations carrying the `-- KICK ENUM REMOVE` header to apply",!1).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let r=await ke({adapter:n,migrationsDir:t.migrationsDir,confirmEnumDrop:e.confirmEnumDrop});r.applied.length===0?console.log(`No pending migrations.`):console.log(`Applied ${r.applied[0]} (batch ${r.batch})`)}finally{await r()}}),n.command(`down`).description(`Reverse the most recent applied migration`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let e=await Te({adapter:n,migrationsDir:t.migrationsDir});e.reversed?console.log(`Reversed ${e.reversed}.`):console.log(`Nothing to reverse.`)}finally{await r()}}),n.command(`rollback`).description(`Reverse the entire last batch as a single unit`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let e=await De({adapter:n,migrationsDir:t.migrationsDir});e.reversed.length===0?console.log(`Nothing to roll back.`):console.log(`Rolled back batch ${e.batch}: ${e.reversed.join(`, `)}`)}finally{await r()}}),n.command(`status`).description(`Print applied + pending migrations`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{oa(await Oe({adapter:n,migrationsDir:t.migrationsDir}))}finally{await r()}}),t.command(`introspect`).description(`Generate a TypeScript schema file from a live database`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`--out <path>`,`Output file (defaults to db.schemaPath from config)`).option(`--json`,`Print the raw SchemaSnapshot JSON to stdout instead of writing TS source`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let r=await n.introspect();if(e.json){console.log(JSON.stringify(r,null,2));return}let i=e.out??t.schemaPath;await O(i,Ae(r),`utf8`);let a=Object.keys(r.tables).length;console.log(`Wrote ${i} (${a} table${a===1?``:`s`}).`)}finally{await r()}})}function ca(e){return e.optsWithGlobals().dryRun??!1}function la(e){e.command(`codemod`).description(`Codebase migration commands (AST-style rewrites — distinct from db migrate)`).command(`modules`).description(`Rewrite module declarations between class form and the defineModule factory.
3868
3885
  Direction defaults to \`modules.style\` from kick.config (or "define").
3869
3886
  --target define|class Override the migration direction.
3870
3887
  --apply Apply the changes (default: dry-run preview).
3871
- --experimental Acknowledge that AST migration is experimental.`).option(`--modules-dir <dir>`,`Modules directory (default: src/modules from kick.config)`).option(`--apply`,`Apply the migration to disk (default: dry-run)`).option(`--experimental`,`Acknowledge that this command is experimental`).option(`--target <style>`,`Migration direction — 'define' or 'class'`).option(`--no-backup`,`Skip the .kickjs/codemod-backups/ snapshot (default: backup on)`).action(async(e,t)=>{let i=Yi(t)||!e.apply;A(i),e.experimental||(console.error(`
3872
- `+k.red(`Error:`)+` kick codemod modules is experimental — pass --experimental to acknowledge.
3888
+ --experimental Acknowledge that AST migration is experimental.`).option(`--modules-dir <dir>`,`Modules directory (default: src/modules from kick.config)`).option(`--apply`,`Apply the migration to disk (default: dry-run)`).option(`--experimental`,`Acknowledge that this command is experimental`).option(`--target <style>`,`Migration direction — 'define' or 'class'`).option(`--no-backup`,`Skip the .kickjs/codemod-backups/ snapshot (default: backup on)`).action(async(e,t)=>{let i=ca(t)||!e.apply;j(i),e.experimental||(console.error(`
3889
+ `+A.red(`Error:`)+` kick codemod modules is experimental — pass --experimental to acknowledge.
3873
3890
  The regex-based rewrite handles the shapes our templates produce.
3874
3891
  Hand-rolled modules with non-standard structures may be skipped.
3875
3892
  Always commit before running with --apply.
3876
- `),process.exit(1));let a=n(await r(process.cwd())),o=C(e.modulesDir??a.dir??`src/modules`),s;e.target===`define`||e.target===`class`?s=e.target:e.target===void 0?s=a.style??`define`:(console.error(`\n ${k.red(`Error:`)} --target must be 'define' or 'class' (got '${e.target}').\n`),process.exit(1));let c=k.dim(`→ ${s}`),l=i?k.dim(`(dry-run)`):k.bold(`(applying)`);console.log(`\n ${k.bold(`kick codemod modules`)} ${c} ${l}`),console.log(` modulesDir: ${k.dim(o)}\n`);let u=e.backup!==!1&&!i,d=await rr(o,{dryRun:i,target:s,backup:u});if(d.backupDir){let e=d.backupDir;console.log(` ${k.green(`✓`)} backup: ${k.dim(e)}\n ${k.dim(`(restore: rm -rf <modulesDir> && mv "<backup>" <modulesDir>)`)}\n`)}else !i&&e.backup===!1&&console.log(` ${k.dim(`(--no-backup — skipping snapshot)`)}\n`);let f=0,p=0;for(let e of d.files)if(e.status===`migrated`)f++,console.log(` ${k.green(`✓`)} ${e.path}`);else{p++;let t=k.dim(`(${e.reason??`skipped`})`);console.log(` ${k.dim(`-`)} ${e.path} ${t}`)}if(console.log(),d.indexStatus===`migrated`)console.log(` ${k.green(`✓`)} ${d.indexPath}`);else if(d.indexStatus===`skipped`){let e=k.dim(`(${d.indexReason??`skipped`})`);console.log(` ${k.dim(`-`)} ${d.indexPath} ${e}`)}else console.log(` ${k.dim(`-`)} ${d.indexPath} ${k.dim(`(not found)`)}`);let m=i?k.dim(` (dry-run — pass --apply to write)`):``;console.log(`\n ${k.bold(String(f))} migrated, ${k.bold(String(p))} skipped${m}\n`)})}const Zi=[`src/db/schema.ts`,`src/db/schema/index.ts`,`src/db/schema`],Qi=()=>({id:`kick/db`,inputs:[`src/db/schema.ts`,`src/db/schema/**/*.ts`],async generate(e){let t=$i(e.cwd);if(!t)return null;let n=y.resolve(e.cwd,`.kickjs/types`);return[`import type { SchemaToTypes, SchemaToRelationsRegister, KickDbClient } from '@forinda/kickjs-db'`,`import type * as appSchema from '${ea(y.relative(n,t)).replace(/\.ts$/,``).replace(/\/index$/,``)}'`,``,`declare global {`,` interface KickDbSchema extends SchemaToTypes<typeof appSchema> {}`,`}`,``,`declare module '@forinda/kickjs-db' {`,` interface KickDbRegister {`,` db: KickDbClient<KickDbSchema>`,` }`,``,` interface KickDbRelationsRegister {`,` db: SchemaToRelationsRegister<typeof appSchema>`,` }`,`}`].join(`
3877
- `)}});function $i(e){for(let t of Zi){let n=y.resolve(e,t);if(t.endsWith(`.ts`)){if(h(n))return n}else{let e=y.join(n,`index.ts`);if(h(e))return e}}return null}function ea(e){return e.replace(/\\/g,`/`)}const ta=()=>({id:`kick/assets`,inputs:[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`],async generate(e){if(!h(y.resolve(e.cwd,`kick.config.ts`)))return null;let t=await r(e.cwd);if(!t?.assetMap)return null;let n=s(t.assetMap,e.cwd);return n.count===0?null:l(n)}}),na="/* eslint-disable */\n// AUTO-GENERATED by `kick typegen`. DO NOT EDIT.\n// Re-run with `kick typegen` or rely on `kick dev` to refresh.\n";function ra(e,t,n){if(e.length===0)return`${na}
3893
+ `),process.exit(1));let a=n(await r(process.cwd())),o=w(e.modulesDir??a.dir??`src/modules`),s;e.target===`define`||e.target===`class`?s=e.target:e.target===void 0?s=a.style??`define`:(console.error(`\n ${A.red(`Error:`)} --target must be 'define' or 'class' (got '${e.target}').\n`),process.exit(1));let c=A.dim(`→ ${s}`),l=i?A.dim(`(dry-run)`):A.bold(`(applying)`);console.log(`\n ${A.bold(`kick codemod modules`)} ${c} ${l}`),console.log(` modulesDir: ${A.dim(o)}\n`);let u=e.backup!==!1&&!i,d=await mr(o,{dryRun:i,target:s,backup:u});if(d.backupDir){let e=d.backupDir;console.log(` ${A.green(`✓`)} backup: ${A.dim(e)}\n ${A.dim(`(restore: rm -rf <modulesDir> && mv "<backup>" <modulesDir>)`)}\n`)}else !i&&e.backup===!1&&console.log(` ${A.dim(`(--no-backup — skipping snapshot)`)}\n`);let f=0,p=0;for(let e of d.files)if(e.status===`migrated`)f++,console.log(` ${A.green(`✓`)} ${e.path}`);else{p++;let t=A.dim(`(${e.reason??`skipped`})`);console.log(` ${A.dim(`-`)} ${e.path} ${t}`)}if(console.log(),d.indexStatus===`migrated`)console.log(` ${A.green(`✓`)} ${d.indexPath}`);else if(d.indexStatus===`skipped`){let e=A.dim(`(${d.indexReason??`skipped`})`);console.log(` ${A.dim(`-`)} ${d.indexPath} ${e}`)}else console.log(` ${A.dim(`-`)} ${d.indexPath} ${A.dim(`(not found)`)}`);let m=i?A.dim(` (dry-run — pass --apply to write)`):``;console.log(`\n ${A.bold(String(f))} migrated, ${A.bold(String(p))} skipped${m}\n`)})}const ua=[`src/db/schema.ts`,`src/db/schema/index.ts`,`src/db/schema`],da=()=>({id:`kick/db`,inputs:[`src/db/schema.ts`,`src/db/schema/**/*.ts`],async generate(e){let t=fa(e.cwd);if(!t)return null;let n=b.resolve(e.cwd,`.kickjs/types`);return[`import type { SchemaToTypes, SchemaToRelationsRegister, KickDbClient } from '@forinda/kickjs-db'`,`import type * as appSchema from '${pa(b.relative(n,t)).replace(/\.ts$/,``).replace(/\/index$/,``)}'`,``,`declare global {`,` interface KickDbSchema extends SchemaToTypes<typeof appSchema> {}`,`}`,``,`declare module '@forinda/kickjs-db' {`,` interface KickDbRegister {`,` db: KickDbClient<KickDbSchema>`,` }`,``,` interface KickDbRelationsRegister {`,` db: SchemaToRelationsRegister<typeof appSchema>`,` }`,`}`].join(`
3894
+ `)}});function fa(e){for(let t of ua){let n=b.resolve(e,t);if(t.endsWith(`.ts`)){if(g(n))return n}else{let e=b.join(n,`index.ts`);if(g(e))return e}}return null}function pa(e){return e.replace(/\\/g,`/`)}const ma=()=>({id:`kick/assets`,inputs:[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`],async generate(e){if(!g(b.resolve(e.cwd,`kick.config.ts`)))return null;let t=await r(e.cwd);if(!t?.assetMap)return null;let n=s(t.assetMap,e.cwd);return n.count===0?null:d(n)}}),ha="/* eslint-disable */\n// AUTO-GENERATED by `kick typegen`. DO NOT EDIT.\n// Re-run with `kick typegen` or rely on `kick dev` to refresh.\n";function ga(e,t,n){if(e.length===0)return`${ha}
3878
3895
  // (no routes discovered yet — annotate a controller method with
3879
3896
  // @Get/@Post/@Put/@Delete/@Patch and re-run \`kick typegen\`)
3880
3897
  declare global {
@@ -3883,8 +3900,8 @@ declare global {
3883
3900
  }
3884
3901
 
3885
3902
  export {}
3886
- `;let r=new Map;for(let t of e){let e=r.get(t.controller)??[];e.push(t),r.set(t.controller,e)}let i=new Map,a=(e,r)=>{let a=oa(e,r,t,n,i);return a?`import('zod').infer<typeof ${a}>`:null},o=[];for(let[e,t]of r){let n=[` interface ${e} {`];for(let e of t){let t=e.pathParams.length>0?`{ ${e.pathParams.map(e=>`${e}: string`).join(`; `)} }`:`{}`,r=a(e.bodySchema,e.filePath),i=a(e.querySchema,e.filePath),o=a(e.paramsSchema,e.filePath)??t,s=r??`unknown`,c=i??ia(e),l=aa(e);n.push(` /**`,` * ${e.httpMethod} ${e.path}`,...l.map(e=>` * ${e}`),` */`,` ${e.method}: {`,` params: ${o}`,` body: ${s}`,` query: ${c}`,` response: unknown`,` }`)}n.push(` }`),o.push(n.join(`
3887
- `))}return`${na}${sa(i)}
3903
+ `;let r=new Map;for(let t of e){let e=r.get(t.controller)??[];e.push(t),r.set(t.controller,e)}let i=new Map,a=(e,r)=>{let a=ya(e,r,t,n,i);return a?`import('zod').infer<typeof ${a}>`:null},o=[];for(let[e,t]of r){let n=[` interface ${e} {`];for(let e of t){let t=e.pathParams.length>0?`{ ${e.pathParams.map(e=>`${e}: string`).join(`; `)} }`:`{}`,r=a(e.bodySchema,e.filePath),i=a(e.querySchema,e.filePath),o=a(e.paramsSchema,e.filePath)??t,s=r??`unknown`,c=i??_a(e),l=va(e);n.push(` /**`,` * ${e.httpMethod} ${e.path}`,...l.map(e=>` * ${e}`),` */`,` ${e.method}: {`,` params: ${o}`,` body: ${s}`,` query: ${c}`,` response: unknown`,` }`)}n.push(` }`),o.push(n.join(`
3904
+ `))}return`${ha}${ba(i)}
3888
3905
  declare global {
3889
3906
  // eslint-disable-next-line @typescript-eslint/no-namespace
3890
3907
  namespace KickRoutes {
@@ -3894,9 +3911,9 @@ ${o.join(`
3894
3911
  }
3895
3912
 
3896
3913
  export {}
3897
- `}function ia(e){if(e.queryFilterable===null)return`unknown`;let t=e.querySortable??[];return`{ filter?: string | string[]; sort?: ${t.length>0?t.flatMap(e=>[`'${e}'`,`'-${e}'`]).join(` | `):`string`}; q?: string; page?: string; limit?: string }`}function aa(e){let t=[];return e.queryFilterable&&e.queryFilterable.length>0&&t.push(`Filterable: ${e.queryFilterable.join(`, `)}`),e.querySortable&&e.querySortable.length>0&&t.push(`Sortable: ${e.querySortable.join(`, `)}`),e.querySearchable&&e.querySearchable.length>0&&t.push(`Searchable: ${e.querySearchable.join(`, `)}`),t}function oa(e,t,n,r,i){if(!e||r!==`zod`||e.source===null)return null;let a=ca(e.source,t,n);if(a===`unknown`)return null;let o=`${a}::${e.identifier}`,s=i.get(o)?.specifier;return s?s=i.get(o).specifier:(s=`_S${i.size}`,i.set(o,{identifier:e.identifier,specifier:s})),s}function sa(e){if(e.size===0)return``;let t=[];for(let[n,r]of e){let[e]=n.split(`::`);t.push(`import type { ${r.identifier} as ${r.specifier} } from '${e}'`)}return t.join(`
3914
+ `}function _a(e){if(e.queryFilterable===null)return`unknown`;let t=e.querySortable??[];return`{ filter?: string | string[]; sort?: ${t.length>0?t.flatMap(e=>[`'${e}'`,`'-${e}'`]).join(` | `):`string`}; q?: string; page?: string; limit?: string }`}function va(e){let t=[];return e.queryFilterable&&e.queryFilterable.length>0&&t.push(`Filterable: ${e.queryFilterable.join(`, `)}`),e.querySortable&&e.querySortable.length>0&&t.push(`Sortable: ${e.querySortable.join(`, `)}`),e.querySearchable&&e.querySearchable.length>0&&t.push(`Searchable: ${e.querySearchable.join(`, `)}`),t}function ya(e,t,n,r,i){if(!e||r!==`zod`||e.source===null)return null;let a=xa(e.source,t,n);if(a===`unknown`)return null;let o=`${a}::${e.identifier}`,s=i.get(o)?.specifier;return s?s=i.get(o).specifier:(s=`_S${i.size}`,i.set(o,{identifier:e.identifier,specifier:s})),s}function ba(e){if(e.size===0)return``;let t=[];for(let[n,r]of e){let[e]=n.split(`::`);t.push(`import type { ${r.identifier} as ${r.specifier} } from '${e}'`)}return t.join(`
3898
3915
  `)+`
3899
- `}function ca(e,t,n){if(e===null)return`unknown`;let r=b(n);if(e===``){let e=S(r,t).split(oe).join(`/`);return e=e.replace(/\.(ts|tsx|mts|cts)$/i,``),e.startsWith(`.`)||(e=`./`+e),e}if(!e.startsWith(`.`)&&!e.startsWith(`/`))return e;let i=S(r,C(b(t),e)).split(oe).join(`/`);return i=i.replace(/\.(ts|tsx|mts|cts)$/i,``),i.startsWith(`.`)||(i=`./`+i),i}const la=()=>({id:`kick/routes`,outExtension:`.ts`,inputs:[`src/**/*.controller.ts`,`src/**/*.module.ts`],async generate(e){let t=await e.getScanResult({root:ua(e),cwd:e.cwd,envFile:da(e)}),n=e.config?.typegen?.schemaValidator??`zod`,r=y.resolve(e.cwd,`.kickjs/types/kick__routes.ts`);return ra(t.routes,r,n)}});function ua(e){return y.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function da(e){let t=e.config?.typegen?.envFile;if(t!==!1)return t}function fa(e,t){if(!e)return null;let n=S(b(t),e.filePath).split(oe).join(`/`);return n=n.replace(/\.(ts|tsx|mts|cts)$/i,``),n.startsWith(`.`)||(n=`./`+n),`/* eslint-disable */
3916
+ `}function xa(e,t,n){if(e===null)return`unknown`;let r=x(n);if(e===``){let e=C(r,t).split(oe).join(`/`);return e=e.replace(/\.(ts|tsx|mts|cts)$/i,``),e.startsWith(`.`)||(e=`./`+e),e}if(!e.startsWith(`.`)&&!e.startsWith(`/`))return e;let i=C(r,w(x(t),e)).split(oe).join(`/`);return i=i.replace(/\.(ts|tsx|mts|cts)$/i,``),i.startsWith(`.`)||(i=`./`+i),i}const Sa=()=>({id:`kick/routes`,outExtension:`.ts`,inputs:[`src/**/*.controller.ts`,`src/**/*.module.ts`],async generate(e){let t=await e.getScanResult({root:Ca(e),cwd:e.cwd,envFile:wa(e)}),n=e.config?.typegen?.schemaValidator??`zod`,r=b.resolve(e.cwd,`.kickjs/types/kick__routes.ts`);return ga(t.routes,r,n)}});function Ca(e){return b.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function wa(e){let t=e.config?.typegen?.envFile;if(t!==!1)return t}function Ta(e,t){if(!e)return null;let n=C(x(t),e.filePath).split(oe).join(`/`);return n=n.replace(/\.(ts|tsx|mts|cts)$/i,``),n.startsWith(`.`)||(n=`./`+n),`/* eslint-disable */
3900
3917
  // AUTO-GENERATED by \`kick typegen\`. DO NOT EDIT.
3901
3918
  // Re-run with \`kick typegen\` or rely on \`kick dev\` to refresh.
3902
3919
 
@@ -3932,4 +3949,4 @@ declare global {
3932
3949
  }
3933
3950
 
3934
3951
  export {}
3935
- `}const pa=()=>({id:`kick/env`,outExtension:`.ts`,inputs:[`src/env.ts`,`src/**/env.ts`,`src/**/*.env.ts`],async generate(e){let t=ha(e);if(t===!1)return null;let n=await e.getScanResult({root:ma(e),cwd:e.cwd,envFile:t});if(!n.env)return null;let r=y.resolve(e.cwd,`.kickjs/types/kick__env.ts`);return fa(n.env,r)}});function ma(e){return y.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function ha(e){return e.config?.typegen?.envFile}var ga=e({builtinCliPlugins:()=>_a});const _a=[o({name:`kick/init`,register:kt}),o({name:`kick/generate`,register:Nr}),o({name:`kick/run`,register:Kr}),o({name:`kick/info`,register:qr}),o({name:`kick/inspect`,register:ni}),o({name:`kick/add`,register:Dt}),o({name:`kick/list`,register:Et}),o({name:`kick/explain`,register:fi}),o({name:`kick/mcp`,register:Ci}),o({name:`kick/tinker`,register:Di}),o({name:`kick/remove`,register:ji}),o({name:`kick/typegen`,register:Pi}),o({name:`kick/check`,register:Ki}),o({name:`kick/db`,register:Ji,typegens:[Qi()]}),o({name:`kick/codemod`,register:Xi}),o({name:`kick/assets`,typegens:[ta()]}),o({name:`kick/routes`,typegens:[la()]}),o({name:`kick/env`,typegens:[pa()]})];export{je as i,ga as n,Lr as r,_a as t};
3952
+ `}const Ea=()=>({id:`kick/env`,outExtension:`.ts`,inputs:[`src/env.ts`,`src/**/env.ts`,`src/**/*.env.ts`],async generate(e){let t=Oa(e);if(t===!1)return null;let n=await e.getScanResult({root:Da(e),cwd:e.cwd,envFile:t});if(!n.env)return null;let r=b.resolve(e.cwd,`.kickjs/types/kick__env.ts`);return Ta(n.env,r)}});function Da(e){return b.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function Oa(e){return e.config?.typegen?.envFile}var ka=e({builtinCliPlugins:()=>Aa});const Aa=[o({name:`kick/init`,register:Pt}),o({name:`kick/generate`,register:Ur}),o({name:`kick/run`,register:ni}),o({name:`kick/info`,register:ri}),o({name:`kick/inspect`,register:pi}),o({name:`kick/add`,register:Mt}),o({name:`kick/list`,register:jt}),o({name:`kick/explain`,register:Ci}),o({name:`kick/mcp`,register:Pi}),o({name:`kick/tinker`,register:Ri}),o({name:`kick/remove`,register:Wi}),o({name:`kick/typegen`,register:qi}),o({name:`kick/check`,register:aa}),o({name:`kick/db`,register:sa,typegens:[da()]}),o({name:`kick/codemod`,register:la}),o({name:`kick/assets`,typegens:[ma()]}),o({name:`kick/routes`,typegens:[Sa()]}),o({name:`kick/env`,typegens:[Ea()]})];export{Me as i,ka as n,qr as r,Aa as t};