@forinda/kickjs-cli 5.11.1 → 6.0.1

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 (37) hide show
  1. package/dist/agent-docs-hbOXsAAh.mjs +12 -0
  2. package/dist/agent-docs-hbOXsAAh.mjs.map +1 -0
  3. package/dist/{builtins-BL1BhYEv.mjs → builtins-Dyk9a-mv.mjs} +2 -2
  4. package/dist/cli.mjs +151 -1376
  5. package/dist/config-DSpcRefL.mjs +13 -0
  6. package/dist/config-DSpcRefL.mjs.map +1 -0
  7. package/dist/doctor-559QZlHi.mjs +1221 -0
  8. package/dist/doctor-559QZlHi.mjs.map +1 -0
  9. package/dist/index.d.mts +663 -853
  10. package/dist/index.d.mts.map +1 -1
  11. package/dist/index.mjs +2 -2
  12. package/dist/{plugin-C4hfxiPw.mjs → plugin-DK01q7wy.mjs} +3 -3
  13. package/dist/{plugin-C4hfxiPw.mjs.map → plugin-DK01q7wy.mjs.map} +1 -1
  14. package/dist/{project-docs-CfB-KVN5.mjs → project-docs-CrfNQIZA.mjs} +6 -36
  15. package/dist/project-docs-CrfNQIZA.mjs.map +1 -0
  16. package/dist/{project-root-CDYKLnfG.mjs → project-root-BdTe6EpE.mjs} +3 -3
  17. package/dist/{project-root-CDYKLnfG.mjs.map → project-root-BdTe6EpE.mjs.map} +1 -1
  18. package/dist/{rolldown-runtime-CeWwRE8g.mjs → rolldown-runtime-CoN4EDcd.mjs} +1 -1
  19. package/dist/run-plugins-BAYoDnFI.mjs +636 -0
  20. package/dist/run-plugins-BAYoDnFI.mjs.map +1 -0
  21. package/dist/typegen-CwtvFZ0t.mjs +114 -0
  22. package/dist/typegen-CwtvFZ0t.mjs.map +1 -0
  23. package/dist/types-BKKzf_bU.mjs +11 -0
  24. package/package.json +13 -13
  25. package/dist/agent-docs-CXqrGZLl.mjs +0 -12
  26. package/dist/agent-docs-CXqrGZLl.mjs.map +0 -1
  27. package/dist/config-Cf8GU8CG.mjs +0 -13
  28. package/dist/config-Cf8GU8CG.mjs.map +0 -1
  29. package/dist/doctor-Dl709LzL.mjs +0 -2076
  30. package/dist/doctor-Dl709LzL.mjs.map +0 -1
  31. package/dist/project-docs-CfB-KVN5.mjs.map +0 -1
  32. package/dist/run-plugins-M_WVt-7a.mjs +0 -976
  33. package/dist/run-plugins-M_WVt-7a.mjs.map +0 -1
  34. package/dist/typegen-CezcLjMb.mjs +0 -114
  35. package/dist/typegen-CezcLjMb.mjs.map +0 -1
  36. package/dist/types-DvYczI2m.mjs +0 -12
  37. package/dist/types-DvYczI2m.mjs.map +0 -1
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs-cli v5.11.1
2
+ * @forinda/kickjs-cli v6.0.1
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,8 +8,8 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{createRequire as e}from"node:module";import{Command as t}from"commander";import{cpSync as n,existsSync as r,mkdirSync as i,readFileSync as a,readdirSync as o,rmSync as s,statSync as c,writeFileSync as l}from"node:fs";import u,{basename as d,dirname as f,extname as p,isAbsolute as m,join as h,parse as g,relative as _,resolve as v,sep as y}from"node:path";import{fileURLToPath as b,pathToFileURL as x}from"node:url";import{execFileSync as ee,execSync as S,fork as te,spawn as ne,spawnSync as re}from"node:child_process";import{access as ie,copyFile as ae,mkdir as oe,readFile as C,readdir as se,rm as ce,stat as le,unlink as ue,writeFile as w}from"node:fs/promises";import*as T from"@clack/prompts";import E from"picocolors";import de from"pluralize";import{glob as fe,globSync as pe}from"glob";import{groupAssetKeys as me}from"@forinda/kickjs";import{arch as he,platform as ge,release as _e}from"node:os";import{detectCompositeReferences as ve,generate as ye,migrateDown as be,migrateLatest as xe,migrateRollback as Se,migrateStatus as Ce,migrateUp as we,renderSchemaSource as Te,resolveDbConfig as Ee}from"@forinda/kickjs-db";var De=Object.defineProperty,D=(e,t)=>{let n={};for(var r in e)De(n,r,{get:e[r],enumerable:!0});return t||De(n,Symbol.toStringTag,{value:`Module`}),n};function Oe(e,t,n){S(e,{cwd:t,stdio:`inherit`,env:n?{...process.env,...n}:process.env})}function ke(e,t,n){let r=re(process.execPath,[e],{cwd:n,stdio:`inherit`,env:{...process.env,...t}});r.status!==0&&process.exit(r.status??1)}function Ae(e,t){if(!t?.commands?.length)return;let n=new Set(e.commands.map(e=>e.name()));for(let r of t.commands){if(n.has(r.name)){console.warn(` Warning: custom command '${r.name}' skipped — conflicts with a built-in command`);continue}je(e,r)}}function je(e,t){let n=e.command(t.name).description(t.description);if(t.aliases)for(let e of t.aliases)n.alias(e);n.allowUnknownOption(!0),n.argument(`[args...]`,`Additional arguments passed to the command`),n.action(e=>{let n=e.join(` `),r=Array.isArray(t.steps)?t.steps:[t.steps];for(let e of r){let r=n?`${e} ${n}`:e;console.log(` $ ${r}`);try{Oe(r)}catch{console.error(` Command failed: ${t.name}`),process.exitCode=1;return}}})}var Me=D({BUILTIN_REPO_TYPES:()=>Pe,PACKAGE_MANAGERS:()=>Ne,defineConfig:()=>Fe,loadKickConfig:()=>k,resolveModuleConfig:()=>O,resolveTokenScope:()=>Ie,validateAssetMap:()=>Be,writeAssetConfigSnapshot:()=>ze});const Ne=[`pnpm`,`npm`,`yarn`,`bun`],Pe=[`drizzle`,`inmemory`,`prisma`];function Fe(e){return e}function Ie(e,t){if(e?.tokenScope&&typeof e.tokenScope==`string`&&e.tokenScope.length>0){let t=Le(e.tokenScope);if(t.length>0)return t}try{let e=h(t,`package.json`);if(r(e)){let t=JSON.parse(a(e,`utf-8`));if(typeof t.name==`string`&&t.name.length>0){let e=t.name.match(/^@([^/]+)\//),n=Le(e?e[1]:t.name);if(n.length>0)return n}}}catch{}return`app`}function Le(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,`-`).replace(/^-+|-+$/g,``).replace(/-{2,}/g,`-`)}function O(e){if(!e)return{};let t={dir:e.modules?.dir,repo:e.modules?.repo,schemaDir:e.modules?.schemaDir,pluralize:e.modules?.pluralize,prismaClientPath:e.modules?.prismaClientPath,style:e.modules?.style};return t.style!==void 0&&t.style!==`define`&&t.style!==`class`&&(console.warn(` Warning: modules.style '${t.style}' is not a valid value (expected 'define' or 'class'). Falling back to 'define'.`),t.style=`define`),t.repo&&typeof t.repo==`string`&&!Pe.includes(t.repo)&&console.warn(` Warning: modules.repo '${t.repo}' is not a built-in type (${Pe.join(`, `)}). It will generate a stub repository. Use { name: '${t.repo}' } to silence this warning.`),t}const Re=[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`,`kick.config.json`];async function k(e){let{findProjectRoot:t}=await Promise.resolve().then(()=>Qt),n=t(e);for(let e of Re){let t=h(n,e);try{await ie(t)}catch{continue}if(e.endsWith(`.json`)){let e=await C(t,`utf-8`);return JSON.parse(e)}if(e.endsWith(`.ts`)){let r;try{r=await import(`jiti`)}catch(t){let n=t instanceof Error?t.message:String(t);n.includes(`Cannot find package 'jiti'`)||n.includes(`ERR_MODULE_NOT_FOUND`)?console.warn(`Warning: Failed to load ${e} — 'jiti' is required for TypeScript configs. Run \`pnpm add -D jiti\` (or your package manager's equivalent), or rename the file to kick.config.js / kick.config.mjs / kick.config.json.`):console.warn(`Warning: Failed to initialize jiti for ${e}: ${n}`);continue}try{let e=await r.createJiti(n,{interopDefault:!0,fsCache:!1}).import(t,{default:!0}),i=Be(e,n);for(let e of i)console.warn(` Warning: ${e}`);return ze(n,e),e}catch(t){let n=t instanceof Error?t.message:String(t);console.warn(`Warning: Failed to load ${e}: ${n}`);continue}}try{let{pathToFileURL:e}=await import(`node:url`),r=await import(e(t).href),i=r.default??r,a=Be(i,n);for(let e of a)console.warn(` Warning: ${e}`);return ze(n,i),i}catch(t){let n=t instanceof Error?t.message:String(t);console.warn(`Warning: Failed to load ${e}: ${n}`);continue}}return null}function ze(e,t){if(!(!t?.assetMap||Object.keys(t.assetMap).length===0))try{let n=h(e,`.kickjs`);i(n,{recursive:!0});let r={version:1,assetMap:t.assetMap,...t.build?.outDir?{build:{outDir:t.build.outDir}}:{}};l(h(n,`kick.config.json`),JSON.stringify(r,null,2)+`
12
- `,`utf-8`)}catch{}}function Be(e,t){let n=[];if(!e?.assetMap)return n;let i=v(t);for(let[a,o]of Object.entries(e.assetMap)){if(!a||a.includes(`/`)){n.push(`assetMap key '${a}' is invalid — must be a non-empty string without '/'`);continue}if(typeof o?.src!=`string`||o.src.length===0){n.push(`assetMap.${a} is missing a non-empty 'src' field`);continue}r(v(t,o.src))||n.push(`assetMap.${a}.src ('${o.src}') does not exist — typegen + build will fail`),o.dest&&Ve(v(t,o.dest),i)&&n.push(`assetMap.${a}.dest ('${o.dest}') resolves outside the project root — refusing to copy`)}return n}function Ve(e,t){let n=_(t,e);return n===``?!1:n.startsWith(`..`)||m(n)}function A(e){return e}var He=class extends Error{constructor(e,t,n){super(`Two plugins registered the same ${e} '${t}': ${n.join(`, `)}. Plugins must use unique ${e} names.`),this.name=`KickPluginConflictError`}};function Ue(e,t=[]){let n=new Map;for(let t of e){let e=(n.get(t.name)??0)+1;if(n.set(t.name,e),e===2)throw new He(`plugin`,t.name,[t.name,t.name])}let r=new Map,i=[];for(let t of e)for(let e of t.commands??[]){let n=r.get(e.name);if(n)throw new He(`command`,e.name,[n,t.name]);r.set(e.name,t.name),i.push(e)}let a=new Set(t.map(e=>e.name)),o=[...i.filter(e=>!a.has(e.name)),...t],s=new Map,c=[];for(let t of e)for(let e of t.typegens??[]){let n=s.get(e.id);if(n)throw new He(`typegen`,e.id,[n,t.name]);s.set(e.id,t.name),c.push(e)}let l=new Map,u=[];for(let t of e)for(let e of t.generators??[]){let n=l.get(e.name);if(n)throw new He(`generator`,e.name,[n,t.name]);l.set(e.name,t.name),u.push({source:t.name,spec:e})}return{commands:o,typegens:c,generators:u,register:async(t,n)=>{let r;if(n)r={generators:u,...n};else{let{findProjectRoot:e}=await Promise.resolve().then(()=>Qt),t=process.cwd();r={cwd:t,projectRoot:e(t),config:null,log:()=>{},generators:u}}for(let n of e)n.register&&await n.register(t,r)}}}var We=D({mergeCliPlugins:()=>Ue});let Ge=!1;function j(e){Ge=e}const Ke=new Set([`.ts`,`.tsx`,`.js`,`.jsx`,`.mjs`,`.cjs`,`.json`,`.md`]);async function M(e,t){Ge||(await oe(f(e),{recursive:!0}),await w(e,t,`utf-8`),Ke.has(p(e))&&await Ye(e,t).catch(()=>{}))}let qe;async function Je(t){if(qe!==void 0)return qe;try{qe=await import(e(h(t,`package.json`)).resolve(`oxfmt`))}catch{qe=null}return qe}async function Ye(e,t){let n=await Je(process.cwd());if(!n)return;let r=await Ze(e);if(r===null)return;let i=await n.format(e,t,r);i.code!==t&&await w(e,i.code,`utf-8`)}const Xe=new Map;async function Ze(e){let t=f(e),n=t;if(Xe.has(n))return Xe.get(n);for(;;){let e=h(t,`.oxfmtrc.json`);if(r(e))try{let t=await C(e,`utf-8`),r=JSON.parse(t);return delete r.$schema,delete r.ignorePatterns,Xe.set(n,r),r}catch{return Xe.set(n,null),null}let i=f(t);if(i===t)return Xe.set(n,null),null;t=i}}async function Qe(e){try{return await ie(e),!0}catch{return!1}}const $e={swagger:`@forinda/kickjs-swagger`,ws:`@forinda/kickjs-ws`,queue:`@forinda/kickjs-queue`,devtools:`@forinda/kickjs-devtools`},et={zod:{name:`zod`,range:`^4.3.6`},valibot:{name:`valibot`,range:`^1.4.1`},yup:{name:`yup`,range:`^1.7.1`}};function tt(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 nt(e,t,n,r=[],i=`zod`){let a=et[i],o={"@forinda/kickjs":tt(n,`@forinda/kickjs`),"@forinda/kickjs-schema":tt(n,`@forinda/kickjs-schema`),dotenv:`^17.3.1`,express:`^5.1.0`,"reflect-metadata":`^0.2.2`,[a.name]:a.range};for(let e of r){let t=$e[e];t&&!o[t]&&(o[t]=tt(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:o,devDependencies:{"@forinda/kickjs-cli":tt(n,`@forinda/kickjs-cli`),"@forinda/kickjs-vite":tt(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 rt(){return`import { defineConfig } from 'vite'
11
+ import{createRequire as e}from"node:module";import{Command as t}from"commander";import{cpSync as n,existsSync as r,mkdirSync as i,readFileSync as a,readdirSync as o,rmSync as s,statSync as c,writeFileSync as l}from"node:fs";import u,{basename as d,dirname as f,extname as p,isAbsolute as m,join as h,parse as g,relative as _,resolve as v,sep as y}from"node:path";import{fileURLToPath as b,pathToFileURL as x}from"node:url";import{execFileSync as S,execSync as C,fork as ee,spawn as te,spawnSync as ne}from"node:child_process";import{access as re,copyFile as ie,mkdir as w,readFile as T,readdir as ae,rm as oe,stat as se,unlink as ce,writeFile as E}from"node:fs/promises";import{KickPluginConflictError as le,defineCliPlugin as D}from"@forinda/kickjs-cli-kit";import*as O from"@clack/prompts";import k from"picocolors";import ue from"pluralize";import{glob as de,globSync as fe}from"glob";import{groupAssetKeys as pe}from"@forinda/kickjs";import{arch as me,platform as he,release as ge}from"node:os";var _e=Object.defineProperty,A=(e,t)=>{let n={};for(var r in e)_e(n,r,{get:e[r],enumerable:!0});return t||_e(n,Symbol.toStringTag,{value:`Module`}),n};function ve(e,t,n){C(e,{cwd:t,stdio:`inherit`,env:n?{...process.env,...n}:process.env})}function ye(e,t,n){let r=ne(process.execPath,[e],{cwd:n,stdio:`inherit`,env:{...process.env,...t}});r.status!==0&&process.exit(r.status??1)}function be(e,t){if(!t?.commands?.length)return;let n=new Set(e.commands.map(e=>e.name()));for(let r of t.commands){if(n.has(r.name)){console.warn(` Warning: custom command '${r.name}' skipped — conflicts with a built-in command`);continue}xe(e,r)}}function xe(e,t){let n=e.command(t.name).description(t.description);if(t.aliases)for(let e of t.aliases)n.alias(e);n.allowUnknownOption(!0),n.argument(`[args...]`,`Additional arguments passed to the command`),n.action(e=>{let n=e.join(` `),r=Array.isArray(t.steps)?t.steps:[t.steps];for(let e of r){let r=n?`${e} ${n}`:e;console.log(` $ ${r}`);try{ve(r)}catch{console.error(` Command failed: ${t.name}`),process.exitCode=1;return}}})}var Se=A({BUILTIN_REPO_TYPES:()=>we,DEPRECATED_REPO_TYPES:()=>Te,PACKAGE_MANAGERS:()=>Ce,defineConfig:()=>De,loadKickConfig:()=>M,resolveModuleConfig:()=>j,resolveTokenScope:()=>Oe,validateAssetMap:()=>Me,warnIfDeprecatedRepo:()=>Ee,writeAssetConfigSnapshot:()=>je});const Ce=[`pnpm`,`npm`,`yarn`,`bun`],we=[`inmemory`],Te=[`prisma`,`drizzle`];function Ee(e){return Te.includes(e)?(console.warn(` Note: the '${e}' repository preset is deprecated. Generating a generic custom repository named '${e}' instead — wire it to your DB by hand. Pass any name via \`--repo <name>\` or \`modules.repo: { name: '<name>' }\`.`),!0):!1}function De(e){return e}function Oe(e,t){if(e?.tokenScope&&typeof e.tokenScope==`string`&&e.tokenScope.length>0){let t=ke(e.tokenScope);if(t.length>0)return t}try{let e=h(t,`package.json`);if(r(e)){let t=JSON.parse(a(e,`utf-8`));if(typeof t.name==`string`&&t.name.length>0){let e=t.name.match(/^@([^/]+)\//),n=ke(e?e[1]:t.name);if(n.length>0)return n}}}catch{}return`app`}function ke(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,`-`).replace(/^-+|-+$/g,``).replace(/-{2,}/g,`-`)}function j(e){if(!e)return{};let t={dir:e.modules?.dir,repo:e.modules?.repo,schemaDir:e.modules?.schemaDir,pluralize:e.modules?.pluralize,prismaClientPath:e.modules?.prismaClientPath,style:e.modules?.style};return t.style!==void 0&&t.style!==`define`&&t.style!==`class`&&(console.warn(` Warning: modules.style '${t.style}' is not a valid value (expected 'define' or 'class'). Falling back to 'define'.`),t.style=`define`),t.repo&&typeof t.repo==`string`&&!we.includes(t.repo)&&(Ee(t.repo)||console.warn(` Warning: modules.repo '${t.repo}' is not a built-in type (${we.join(`, `)}). It will generate a stub repository. Use { name: '${t.repo}' } to silence this warning.`)),t}const Ae=[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`,`kick.config.json`];async function M(e){let{findProjectRoot:t}=await Promise.resolve().then(()=>Ut),n=t(e);for(let e of Ae){let t=h(n,e);try{await re(t)}catch{continue}if(e.endsWith(`.json`)){let e=await T(t,`utf-8`);return JSON.parse(e)}if(e.endsWith(`.ts`)){let r;try{r=await import(`jiti`)}catch(t){let n=t instanceof Error?t.message:String(t);n.includes(`Cannot find package 'jiti'`)||n.includes(`ERR_MODULE_NOT_FOUND`)?console.warn(`Warning: Failed to load ${e} — 'jiti' is required for TypeScript configs. Run \`pnpm add -D jiti\` (or your package manager's equivalent), or rename the file to kick.config.js / kick.config.mjs / kick.config.json.`):console.warn(`Warning: Failed to initialize jiti for ${e}: ${n}`);continue}try{let e=await r.createJiti(n,{interopDefault:!0,fsCache:!1}).import(t,{default:!0}),i=Me(e,n);for(let e of i)console.warn(` Warning: ${e}`);return je(n,e),e}catch(t){let n=t instanceof Error?t.message:String(t);console.warn(`Warning: Failed to load ${e}: ${n}`);continue}}try{let{pathToFileURL:e}=await import(`node:url`),r=await import(e(t).href),i=r.default??r,a=Me(i,n);for(let e of a)console.warn(` Warning: ${e}`);return je(n,i),i}catch(t){let n=t instanceof Error?t.message:String(t);console.warn(`Warning: Failed to load ${e}: ${n}`);continue}}return null}function je(e,t){if(!(!t?.assetMap||Object.keys(t.assetMap).length===0))try{let n=h(e,`.kickjs`);i(n,{recursive:!0});let r={version:1,assetMap:t.assetMap,...t.build?.outDir?{build:{outDir:t.build.outDir}}:{}};l(h(n,`kick.config.json`),JSON.stringify(r,null,2)+`
12
+ `,`utf-8`)}catch{}}function Me(e,t){let n=[];if(!e?.assetMap)return n;let i=v(t);for(let[a,o]of Object.entries(e.assetMap)){if(!a||a.includes(`/`)){n.push(`assetMap key '${a}' is invalid — must be a non-empty string without '/'`);continue}if(typeof o?.src!=`string`||o.src.length===0){n.push(`assetMap.${a} is missing a non-empty 'src' field`);continue}r(v(t,o.src))||n.push(`assetMap.${a}.src ('${o.src}') does not exist — typegen + build will fail`),o.dest&&Ne(v(t,o.dest),i)&&n.push(`assetMap.${a}.dest ('${o.dest}') resolves outside the project root — refusing to copy`)}return n}function Ne(e,t){let n=_(t,e);return n===``?!1:n.startsWith(`..`)||m(n)}function Pe(e,t=[]){let n=new Map;for(let t of e){let e=(n.get(t.name)??0)+1;if(n.set(t.name,e),e===2)throw new le(`plugin`,t.name,[t.name,t.name])}let r=new Map,i=[];for(let t of e)for(let e of t.commands??[]){let n=r.get(e.name);if(n)throw new le(`command`,e.name,[n,t.name]);r.set(e.name,t.name),i.push(e)}let a=new Set(t.map(e=>e.name)),o=[...i.filter(e=>!a.has(e.name)),...t],s=new Map,c=[];for(let t of e)for(let e of t.typegens??[]){let n=s.get(e.id);if(n)throw new le(`typegen`,e.id,[n,t.name]);s.set(e.id,t.name),c.push(e)}let l=new Map,u=[];for(let t of e)for(let e of t.generators??[]){let n=l.get(e.name);if(n)throw new le(`generator`,e.name,[n,t.name]);l.set(e.name,t.name),u.push({source:t.name,spec:e})}return{commands:o,typegens:c,generators:u,register:async(t,n)=>{let r;if(n)r={generators:u,...n};else{let{findProjectRoot:e}=await Promise.resolve().then(()=>Ut),t=process.cwd();r={cwd:t,projectRoot:e(t),config:null,log:()=>{},generators:u}}for(let n of e)n.register&&await n.register(t,r)}}}var Fe=A({mergeCliPlugins:()=>Pe});let Ie=!1;function N(e){Ie=e}const Le=new Set([`.ts`,`.tsx`,`.js`,`.jsx`,`.mjs`,`.cjs`,`.json`,`.md`]);async function P(e,t){Ie||(await w(f(e),{recursive:!0}),await E(e,t,`utf-8`),Le.has(p(e))&&await Be(e,t).catch(()=>{}))}let Re;async function ze(t){if(Re!==void 0)return Re;try{Re=await import(e(h(t,`package.json`)).resolve(`oxfmt`))}catch{Re=null}return Re}async function Be(e,t){let n=await ze(process.cwd());if(!n)return;let r=await He(e);if(r===null)return;let i=await n.format(e,t,r);i.code!==t&&await E(e,i.code,`utf-8`)}const Ve=new Map;async function He(e){let t=f(e),n=t;if(Ve.has(n))return Ve.get(n);for(;;){let e=h(t,`.oxfmtrc.json`);if(r(e))try{let t=await T(e,`utf-8`),r=JSON.parse(t);return delete r.$schema,delete r.ignorePatterns,Ve.set(n,r),r}catch{return Ve.set(n,null),null}let i=f(t);if(i===t)return Ve.set(n,null),null;t=i}}async function Ue(e){try{return await re(e),!0}catch{return!1}}const We={swagger:`@forinda/kickjs-swagger`,ws:`@forinda/kickjs-ws`,queue:`@forinda/kickjs-queue`,devtools:`@forinda/kickjs-devtools`},Ge={zod:{name:`zod`,range:`^4.3.6`},valibot:{name:`valibot`,range:`^1.4.1`},yup:{name:`yup`,range:`^1.7.1`}};function Ke(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 qe(e,t,n,r=[],i=`zod`){let a=Ge[i],o={"@forinda/kickjs":Ke(n,`@forinda/kickjs`),"@forinda/kickjs-schema":Ke(n,`@forinda/kickjs-schema`),dotenv:`^17.3.1`,express:`^5.1.0`,"reflect-metadata":`^0.2.2`,[a.name]:a.range};for(let e of r){let t=We[e];t&&!o[t]&&(o[t]=Ke(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:o,devDependencies:{"@forinda/kickjs-cli":Ke(n,`@forinda/kickjs-cli`),"@forinda/kickjs-vite":Ke(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 Je(){return`import { defineConfig } from 'vite'
13
13
  import { resolve } from 'node:path'
14
14
  import swc from 'unplugin-swc'
15
15
  import { kickjsVitePlugin, envWatchPlugin } from '@forinda/kickjs-vite'
@@ -39,7 +39,7 @@ export default defineConfig({
39
39
  },
40
40
  },
41
41
  })
42
- `}function it(){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 at(){return JSON.stringify({semi:!1,singleQuote:!0,trailingComma:`all`,printWidth:100,tabWidth:2},null,2)}function ot(){return`# https://editorconfig.org
42
+ `}function Ye(){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 Xe(){return JSON.stringify({semi:!1,singleQuote:!0,trailingComma:`all`,printWidth:100,tabWidth:2},null,2)}function Ze(){return`# https://editorconfig.org
43
43
  root = true
44
44
 
45
45
  [*]
@@ -52,14 +52,14 @@ insert_final_newline = true
52
52
 
53
53
  [*.md]
54
54
  trim_trailing_whitespace = false
55
- `}function st(){return`node_modules/
55
+ `}function Qe(){return`node_modules/
56
56
  dist/
57
57
  .env
58
58
  coverage/
59
59
  .DS_Store
60
60
  *.tsbuildinfo
61
61
  .kickjs/
62
- `}function ct(){return`# Auto-detect text files and normalise line endings to LF
62
+ `}function $e(){return`# Auto-detect text files and normalise line endings to LF
63
63
  * text=auto eol=lf
64
64
 
65
65
  # Explicitly mark generated / binary files
@@ -77,11 +77,11 @@ coverage/
77
77
  pnpm-lock.yaml -diff linguist-generated
78
78
  yarn.lock -diff linguist-generated
79
79
  package-lock.json -diff linguist-generated
80
- `}function lt(){return`PORT=3000
80
+ `}function et(){return`PORT=3000
81
81
  NODE_ENV=development
82
- `}function ut(){return`PORT=3000
82
+ `}function tt(){return`PORT=3000
83
83
  NODE_ENV=development
84
- `}function dt(){return`import { defineConfig } from 'vitest/config'
84
+ `}function nt(){return`import { defineConfig } from 'vitest/config'
85
85
  import swc from 'unplugin-swc'
86
86
 
87
87
  export default defineConfig({
@@ -92,33 +92,7 @@ export default defineConfig({
92
92
  include: ['src/**/*.test.ts'],
93
93
  },
94
94
  })
95
- `}function ft(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'
96
- // Side-effect import — registers the extended env schema with kickjs
97
- // **before** any controller / service / @Value gets resolved. Without
98
- // this line ConfigService.get('YOUR_KEY') returns undefined because the
99
- // cached schema would still be the base shape. See guide/configuration.
100
- import './config'
101
- import { bootstrap } from '@forinda/kickjs'
102
- // import { WsAdapter } from '@forinda/kickjs-ws'
103
- // import { QueueAdapter, BullMQProvider } from '@forinda/kickjs-queue'
104
- ${t.length?t.join(`
105
- `)+`
106
- `:``}import { modules } from './modules'
107
-
108
- // Export the app for the Vite plugin (dev mode)
109
- export const app = await bootstrap({
110
- modules,${t.length?`\n adapters: [\n${i.join(`
111
- `)}\n // Uncomment for WebSocket support:\n // WsAdapter(),\n // Uncomment when Redis is available:\n // QueueAdapter({\n // provider: new BullMQProvider({ host: 'localhost', port: 6379 }),\n // }),\n ],`:`
112
- adapters: [
113
- // Uncomment for WebSocket support:
114
- // WsAdapter(),
115
- // Uncomment when Redis is available:
116
- // QueueAdapter({
117
- // provider: new BullMQProvider({ host: 'localhost', port: 6379 }),
118
- // }),
119
- ],`}
120
- })
121
- `}case`minimal`:{let t=[],i=[];return r.includes(`swagger`)&&(t.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`),i.push(` SwaggerAdapter({ info: { title: '${e}', version: '${n}' } }),`)),r.includes(`devtools`)&&(t.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`),i.push(` DevToolsAdapter(),`)),`import 'reflect-metadata'
95
+ `}function rt(e,t,n,r=[]){switch(t){case`minimal`:{let t=[],i=[];return r.includes(`swagger`)&&(t.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`),i.push(` SwaggerAdapter({ info: { title: '${e}', version: '${n}' } }),`)),r.includes(`devtools`)&&(t.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`),i.push(` DevToolsAdapter(),`)),`import 'reflect-metadata'
122
96
  // Side-effect import — registers the extended env schema with kickjs
123
97
  // **before** any controller / service / @Value gets resolved. Without
124
98
  // this line ConfigService.get('YOUR_KEY') returns undefined because the
@@ -162,14 +136,14 @@ export const app = await bootstrap({
162
136
  express.json(),
163
137
  ],
164
138
  })
165
- `}}}function pt(){return`import { defineModules } from '@forinda/kickjs'
139
+ `}}}function it(){return`import { defineModules } from '@forinda/kickjs'
166
140
  import { HelloModule } from './hello/hello.module'
167
141
 
168
142
  // Remove HelloModule and run: kick g module <name>
169
143
  // \`defineModules()\` returns a chainable list — \`kick g module\` appends
170
144
  // \`.mount(NewModule())\` to the chain on every generation.
171
145
  export const modules = defineModules().mount(HelloModule())
172
- `}function mt(e=`zod`){return e===`valibot`?`import { loadEnvFromSchema } from '@forinda/kickjs/config'
146
+ `}function at(e=`zod`){return e===`valibot`?`import { loadEnvFromSchema } from '@forinda/kickjs/config'
173
147
  import { fromValibot } from '@forinda/kickjs-schema/valibot'
174
148
  import * as v from 'valibot'
175
149
 
@@ -297,7 +271,7 @@ const envSchema = fromZod(
297
271
  export const env = loadEnvFromSchema(envSchema)
298
272
 
299
273
  export default envSchema
300
- `}function ht(){return`import { Service } from '@forinda/kickjs'
274
+ `}function ot(){return`import { Service } from '@forinda/kickjs'
301
275
 
302
276
  @Service()
303
277
  export class HelloService {
@@ -309,7 +283,7 @@ export class HelloService {
309
283
  return { status: 'ok', uptime: process.uptime() }
310
284
  }
311
285
  }
312
- `}function gt(){return`import { Controller, Get, Autowired, type Ctx } from '@forinda/kickjs'
286
+ `}function st(){return`import { Controller, Get, Autowired, type Ctx } from '@forinda/kickjs'
313
287
  import { HelloService } from './hello.service'
314
288
 
315
289
  // \`Ctx<KickRoutes.HelloController['<method>']>\` is generated by
@@ -331,7 +305,7 @@ export class HelloController {
331
305
  ctx.json(this.helloService.healthCheck())
332
306
  }
333
307
  }
334
- `}function _t(){return`import { defineModule } from '@forinda/kickjs'
308
+ `}function ct(){return`import { defineModule } from '@forinda/kickjs'
335
309
  import { HelloController } from './hello.controller'
336
310
 
337
311
  export const HelloModule = defineModule({
@@ -352,7 +326,7 @@ export const HelloModule = defineModule({
352
326
  },
353
327
  }),
354
328
  })
355
- `}function vt(e,t=`inmemory`,n=`pnpm`){return`import { defineConfig } from '@forinda/kickjs-cli'
329
+ `}function lt(e,t=`inmemory`,n=`pnpm`){return`import { defineConfig } from '@forinda/kickjs-cli'
356
330
 
357
331
  export default defineConfig({
358
332
  pattern: '${e}',
@@ -361,7 +335,7 @@ export default defineConfig({
361
335
  packageManager: '${n}',
362
336
  modules: {
363
337
  dir: 'src/modules',
364
- repo: ${[`drizzle`,`inmemory`,`prisma`].includes(t)?`'${t}'`:`{ name: '${t}' }`},
338
+ repo: ${t===`inmemory`?`'inmemory'`:`{ name: '${t}' }`},
365
339
  pluralize: true,
366
340
  },
367
341
 
@@ -399,7 +373,7 @@ export default defineConfig({
399
373
  },
400
374
  ],
401
375
  })
402
- `}function yt(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}
376
+ `}function ut(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`),`# ${e}
403
377
 
404
378
  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.
405
379
 
@@ -462,7 +436,7 @@ Copy \`.env.example\` to \`.env\` and configure:
462
436
 
463
437
  - [KickJS Documentation](https://forinda.github.io/kick-js/)
464
438
  - [CLI Reference](https://forinda.github.io/kick-js/api/cli.html)
465
- `}function bt(e,t,n){return`# CLAUDE.md — ${e}
439
+ `}function dt(e,t,n){return`# CLAUDE.md — ${e}
466
440
 
467
441
  **Read \`./.agents/AGENTS.md\` first.** It is the canonical, multi-agent
468
442
  reference for this project (Claude, Copilot, Codex, Gemini, etc.) —
@@ -536,7 +510,7 @@ When generating or modifying code in this project, stay aligned with the v4 conv
536
510
  - **Refresh these files**: \`kick g agents -f\` regenerates \`CLAUDE.md\` at the project root and \`.agents/AGENTS.md\` + \`.agents/GEMINI.md\` + \`.agents/COPILOT.md\` + every \`.agents/skills/<name>/SKILL.md\` from the latest CLI templates. Hand-edited content is overwritten — keep customisation in \`.agents/AGENTS.local.md\` or per-skill \`SKILL.local.md\` files alongside.
537
511
 
538
512
  For everything else (controllers, services, modules, RequestContext API, generators, CLI commands, package additions, env wiring, troubleshooting) → \`.agents/AGENTS.md\`.
539
- `}function xt(e,t,n){return`# AGENTS.md — AI Agent Guide for ${e}
513
+ `}function ft(e,t,n){return`# AGENTS.md — AI Agent Guide for ${e}
540
514
 
541
515
  This guide is the **canonical, multi-agent reference** for this KickJS
542
516
  application — Claude, Copilot, Codex, Gemini, etc. all read it first.
@@ -700,34 +674,12 @@ package additions, env access patterns, troubleshooting) is detailed below.
700
674
 
701
675
  Each module in \`src/modules/<name>/\` typically contains:
702
676
 
703
- ${t===`ddd`?`\`\`\`
677
+ ${t===`rest`?`\`\`\`
704
678
  <name>/
705
679
  ├── <name>.controller.ts # HTTP routes (@Controller)
706
680
  ├── <name>.service.ts # Business logic (@Service)
707
681
  ├── <name>.repository.ts # Data access (@Repository)
708
- ├── <name>.dto.ts # Request/response schemas (Zod)
709
- ├── <name>.entity.ts # Domain entity (optional)
710
- └── <name>.module.ts # Module definition (defineModule factory)
711
- \`\`\`
712
- `:t===`cqrs`?`\`\`\`
713
- <name>/
714
- ├── commands/ # Write operations
715
- │ ├── create-<name>.command.ts
716
- │ └── create-<name>.handler.ts
717
- ├── queries/ # Read operations
718
- │ ├── get-<name>.query.ts
719
- │ └── get-<name>.handler.ts
720
- ├── events/ # Domain events
721
- │ └── <name>-created.event.ts
722
- ├── <name>.controller.ts # HTTP routes
723
- ├── <name>.repository.ts # Data access
724
- └── <name>.module.ts # Module definition (defineModule factory)
725
- \`\`\`
726
- `:t===`rest`?`\`\`\`
727
- <name>/
728
- ├── <name>.controller.ts # HTTP routes (@Controller)
729
- ├── <name>.service.ts # Business logic (@Service)
730
- ├── <name>.dto.ts # Request/response schemas (Zod)
682
+ ├── dtos/ # Request/response schemas (Zod)
731
683
  └── <name>.module.ts # Module definition (defineModule factory)
732
684
  \`\`\`
733
685
  `:"```\nsrc/\n├── index.ts # Add routes here\n└── ... # Custom structure\n```\n"}
@@ -992,15 +944,7 @@ fast). The \`onError\` hook is async-permitted.
992
944
 
993
945
  Full guide: <https://forinda.github.io/kick-js/guide/context-decorators>.
994
946
 
995
- ${t===`cqrs`?`### Background Jobs
996
- | Decorator | Purpose |
997
- |-----------|---------|
998
- | \`@Job('name')\` | Queue job handler |
999
- | \`@Process('queue')\` | Queue processor |
1000
- | \`@Cron('0 * * * *')\` | Cron schedule |
1001
- | \`@WsController()\` | WebSocket controller |
1002
-
1003
- `:``}## Common Pitfalls
947
+ ## Common Pitfalls
1004
948
 
1005
949
  1. **Forgot to register module** — Add to \`src/modules/index.ts\` exports array
1006
950
  2. **DI not working** — Ensure \`reflect-metadata\` is imported in \`src/index.ts\`
@@ -1043,7 +987,7 @@ ${t===`cqrs`?`### Background Jobs
1043
987
  - [Decorators Guide](https://forinda.github.io/kick-js/guide/decorators.html)
1044
988
  - [DI System](https://forinda.github.io/kick-js/guide/dependency-injection.html)
1045
989
  - [Testing](https://forinda.github.io/kick-js/api/testing.html)
1046
- `}function St(e,t,n){let r=`<!-- Generated by \`kick g agents\` for ${e}. Edits are overwritten on the next refresh; keep customisation in a SKILL.local.md alongside. -->`;return[{slug:`add-module`,frontmatterName:`kickjs-add-module`,description:`Use when the user asks to add a new feature module (controller + service + repo + DTOs).`,body:`**Trigger phrases**: "add a users module", "scaffold tasks", "new feature for X".
990
+ `}function pt(e,t,n){let r=`<!-- Generated by \`kick g agents\` for ${e}. Edits are overwritten on the next refresh; keep customisation in a SKILL.local.md alongside. -->`;return[{slug:`add-module`,frontmatterName:`kickjs-add-module`,description:`Use when the user asks to add a new feature module (controller + service + repo + DTOs).`,body:`**Trigger phrases**: "add a users module", "scaffold tasks", "new feature for X".
1047
991
 
1048
992
  **Steps**:
1049
993
  1. Run \`kick g module <name>\` (use plural form if the project pluralizes — check \`kick.config.ts\`).
@@ -1178,7 +1122,7 @@ description: ${e.description}
1178
1122
  ${r}
1179
1123
 
1180
1124
  ${e.body}
1181
- `}))}function Ct(e,t,n){return`# GEMINI.md — ${e}
1125
+ `}))}function mt(e,t,n){return`# GEMINI.md — ${e}
1182
1126
 
1183
1127
  **Read \`./AGENTS.md\` first.** It is the canonical, multi-agent
1184
1128
  reference for this project — every convention, structure, decorator
@@ -1212,7 +1156,7 @@ without us copy-pasting.
1212
1156
  \`kick g agents --only gemini -f\` regenerates this file from the
1213
1157
  CLI template. Hand-edited content is overwritten — keep customisation
1214
1158
  in \`.agents/GEMINI.local.md\`.
1215
- `}function wt(e,t,n){return`# COPILOT.md — ${e}
1159
+ `}function ht(e,t,n){return`# COPILOT.md — ${e}
1216
1160
 
1217
1161
  **Read \`./AGENTS.md\` first.** It is the canonical, multi-agent
1218
1162
  reference for this project — every convention, structure, decorator
@@ -1245,103 +1189,16 @@ Codex / Cursor / Gemini / Claude Code without copy-pasting.
1245
1189
  \`kick g agents --only copilot -f\` regenerates this file from the
1246
1190
  CLI template. Hand-edited content is overwritten — keep customisation
1247
1191
  in \`.agents/COPILOT.local.md\`.
1248
- `}const Tt=f(b(import.meta.url)),Et=JSON.parse(a(h(Tt,`..`,`package.json`),`utf-8`)),Dt=`^${Et.version}`,Ot=[`@forinda/kickjs`,`@forinda/kickjs-cli`,`@forinda/kickjs-schema`,`@forinda/kickjs-vite`,`@forinda/kickjs-swagger`,`@forinda/kickjs-ws`,`@forinda/kickjs-queue`,`@forinda/kickjs-devtools`,`@forinda/kickjs-testing`];async function kt(){let e=await Promise.all(Ot.map(async e=>{try{let t=ee(`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 At(e){let{name:t,directory:n,packageManager:r=`pnpm`,template:i=`rest`,defaultRepo:a=`inmemory`,packages:o=[],schemaLib:s=`zod`}=e,c=n,l=e=>console.log(` ${e}`);console.log(`\n Creating KickJS project: ${t}\n`),l(`Resolving package versions...`);let u=await kt();await M(h(c,`package.json`),nt(t,i,u,o,s)),await M(h(c,`vite.config.ts`),rt()),await M(h(c,`tsconfig.json`),it()),await M(h(c,`.prettierrc`),at()),await M(h(c,`.editorconfig`),ot()),await M(h(c,`.gitignore`),st()),await M(h(c,`.gitattributes`),ct()),await M(h(c,`.env`),lt()),await M(h(c,`.env.example`),ut()),await M(h(c,`src/config/index.ts`),mt(s)),await M(h(c,`src/index.ts`),ft(t,i,Et.version,o)),await M(h(c,`src/modules/index.ts`),pt()),await M(h(c,`src/modules/hello/hello.service.ts`),ht()),await M(h(c,`src/modules/hello/hello.controller.ts`),gt()),await M(h(c,`src/modules/hello/hello.module.ts`),_t()),await M(h(c,`kick.config.ts`),vt(i,a,r)),await M(h(c,`vitest.config.ts`),dt()),await M(h(c,`README.md`),yt(t,i,r));let{generateAgentDocs:d}=await Promise.resolve().then(()=>xr);if(await d({outDir:c,name:t,pm:r,template:i,only:`all`,force:!0}),e.installDeps){console.log(`\n Installing dependencies with ${r}...\n`);try{S(`${r} install`,{cwd:c,stdio:`inherit`}),console.log(`
1249
- Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${r} install failed. Run it manually.`)}}try{let{runTypegen:e}=await Promise.resolve().then(()=>_a);await e({cwd:c,allowDuplicates:!0,silent:!0})}catch{}if(e.initGit)try{S(`git init`,{cwd:c,stdio:`pipe`}),S(`git branch -M main`,{cwd:c,stdio:`pipe`}),S(`git add -A`,{cwd:c,stdio:`pipe`}),S(`git commit -m "chore: initial commit from kick new"`,{cwd:c,stdio:`pipe`}),l(`Git repository initialized`)}catch{l(`Warning: git init failed (git may not be installed)`)}console.log(`
1250
- Project scaffolded successfully!`),console.log();let f=c!==process.cwd();l(`Next steps:`),f&&l(` cd ${t}`),e.installDeps||l(` ${r} install`);let p={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`};l(` ${p[i]??p.rest}`),l(` kick dev`),l(``),l(`Commands:`),l(` kick dev Start dev server with Vite HMR`),l(` kick build Production build via Vite`),l(` kick start Run production build`),l(``),l(`Generators:`),l(` kick g module <name> Full DDD module (controller, DTOs, use-cases, repo)`),l(` kick g scaffold <n> <f..> CRUD module from field definitions`),l(` kick g controller <name> Standalone controller`),l(` kick g service <name> @Service() class`),l(` kick g middleware <name> Express middleware`),l(` kick g guard <name> Route guard (auth, roles, etc.)`),l(` kick g adapter <name> AppAdapter with lifecycle hooks`),l(` kick g dto <name> Zod DTO schema`),i===`cqrs`&&l(` kick g job <name> Queue job processor`),l(` kick g config Generate kick.config.ts`),l(``),l(`Add packages:`),l(` kick add <pkg> Install a KickJS package + peers`),l(` kick add --list Show all available packages`),l(``),l(`Available: auth, swagger, drizzle, prisma, ws, queue, devtools, mcp, testing`),l(``)}const jt={GET:E.green,POST:E.cyan,PUT:E.yellow,PATCH:E.magenta,DELETE:E.red};function Mt(e){return(jt[e]??E.dim)(e.padEnd(7))}function Nt(e){let t=`[${e}]`.padEnd(10);switch(e){case`CRITICAL`:return E.red(t);case`WARNING`:return E.yellow(t);case`INFO`:return E.blue(E.dim(t));default:return t}}E.green(`✓`),E.red(`✖`),E.yellow(`⚠`),E.blue(`ℹ`);function Pt(e){T.intro(E.bgCyan(E.black(` ${e} `)))}function N(e){T.outro(e)}function Ft(e){T.isCancel(e)&&(T.cancel(`Operation cancelled.`),process.exit(0))}async function It(e){let t=await T.text(e);return Ft(t),t}async function Lt(e){let t=await T.select(e);return Ft(t),t}async function Rt(e){let t=await T.multiselect(e);return Ft(t),t}async function P(e){let t=await T.confirm(e);return Ft(t),t}function zt(){return T.spinner()}const F=T.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},queue:{pkg:`@forinda/kickjs-queue`,peers:[],description:`Queue adapter (BullMQ/RabbitMQ/Kafka)`},"queue:bullmq":{pkg:`@forinda/kickjs-queue`,peers:[`bullmq`,`ioredis`],description:`Queue with BullMQ + Redis`},"queue:rabbitmq":{pkg:`@forinda/kickjs-queue`,peers:[`amqplib`],description:`Queue with RabbitMQ`},"queue:kafka":{pkg:`@forinda/kickjs-queue`,peers:[`kafkajs`],description:`Queue with Kafka`},"queue:redis-pubsub":{pkg:`@forinda/kickjs-queue`,peers:[`ioredis`],description:`Lightweight pub/sub via Redis (no persistence)`},mcp:{pkg:`@forinda/kickjs-mcp`,peers:[`@modelcontextprotocol/sdk`],description:`Model Context Protocol server — expose @Controller endpoints as AI tools`},testing:{pkg:`@forinda/kickjs-testing`,peers:[],description:`Test utilities and TestModule builder`,dev:!0}};function Vt(e,t=process.cwd()){let n=t;for(;;){if(r(v(n,e)))return n;let t=f(n);if(t===n)return null;n=t}}function Ht(){return Vt(`pnpm-lock.yaml`)?`pnpm`:Vt(`yarn.lock`)?`yarn`:Vt(`bun.lockb`)||Vt(`bun.lock`)?`bun`:Vt(`package-lock.json`)?`npm`:null}function Ut(){let e=process.cwd();for(;e;){let t=v(e,`package.json`);if(r(t))try{let e=JSON.parse(a(t,`utf-8`)).packageManager;if(typeof e==`string`){let t=e.split(`@`)[0];if(Ne.includes(t))return t}}catch{}let n=f(e);if(n===e)return null;e=n}return null}async function Wt(e){if(e&&Ne.includes(e))return{pm:e,source:`flag`};let t=await k(process.cwd());if(t?.packageManager&&Ne.includes(t.packageManager))return{pm:t.packageManager,source:`config`};let n=Ut();if(n)return{pm:n,source:`package.json`};let r=Ht();return r?{pm:r,source:`lockfile`}:{pm:`npm`,source:`default`}}async function Gt(e){let{pm:t}=await Wt(e);return t}function Kt(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(`
1192
+ `}const gt=f(b(import.meta.url)),_t=JSON.parse(a(h(gt,`..`,`package.json`),`utf-8`)),vt=`^${_t.version}`,yt=[`@forinda/kickjs`,`@forinda/kickjs-cli`,`@forinda/kickjs-schema`,`@forinda/kickjs-vite`,`@forinda/kickjs-swagger`,`@forinda/kickjs-ws`,`@forinda/kickjs-queue`,`@forinda/kickjs-devtools`,`@forinda/kickjs-testing`];async function bt(){let e=await Promise.all(yt.map(async e=>{try{let t=S(`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,vt]}));return Object.fromEntries(e)}async function xt(e){let{name:t,directory:n,packageManager:r=`pnpm`,template:i=`rest`,defaultRepo:a=`inmemory`,packages:o=[],schemaLib:s=`zod`}=e,c=n,l=e=>console.log(` ${e}`);console.log(`\n Creating KickJS project: ${t}\n`),l(`Resolving package versions...`);let u=await bt();await P(h(c,`package.json`),qe(t,i,u,o,s)),await P(h(c,`vite.config.ts`),Je()),await P(h(c,`tsconfig.json`),Ye()),await P(h(c,`.prettierrc`),Xe()),await P(h(c,`.editorconfig`),Ze()),await P(h(c,`.gitignore`),Qe()),await P(h(c,`.gitattributes`),$e()),await P(h(c,`.env`),et()),await P(h(c,`.env.example`),tt()),await P(h(c,`src/config/index.ts`),at(s)),await P(h(c,`src/index.ts`),rt(t,i,_t.version,o)),await P(h(c,`src/modules/index.ts`),it()),await P(h(c,`src/modules/hello/hello.service.ts`),ot()),await P(h(c,`src/modules/hello/hello.controller.ts`),st()),await P(h(c,`src/modules/hello/hello.module.ts`),ct()),await P(h(c,`kick.config.ts`),lt(i,a,r)),await P(h(c,`vitest.config.ts`),nt()),await P(h(c,`README.md`),ut(t,i,r));let{generateAgentDocs:d}=await Promise.resolve().then(()=>Kn);if(await d({outDir:c,name:t,pm:r,template:i,only:`all`,force:!0}),e.installDeps){console.log(`\n Installing dependencies with ${r}...\n`);try{C(`${r} install`,{cwd:c,stdio:`inherit`}),console.log(`
1193
+ Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${r} install failed. Run it manually.`)}}try{let{runTypegen:e}=await Promise.resolve().then(()=>Ui);await e({cwd:c,allowDuplicates:!0,silent:!0})}catch{}if(e.initGit)try{C(`git init`,{cwd:c,stdio:`pipe`}),C(`git branch -M main`,{cwd:c,stdio:`pipe`}),C(`git add -A`,{cwd:c,stdio:`pipe`}),C(`git commit -m "chore: initial commit from kick new"`,{cwd:c,stdio:`pipe`}),l(`Git repository initialized`)}catch{l(`Warning: git init failed (git may not be installed)`)}console.log(`
1194
+ Project scaffolded successfully!`),console.log();let f=c!==process.cwd();l(`Next steps:`),f&&l(` cd ${t}`),e.installDeps||l(` ${r} install`);let p={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`};l(` ${p[i]??p.rest}`),l(` kick dev`),l(``),l(`Commands:`),l(` kick dev Start dev server with Vite HMR`),l(` kick build Production build via Vite`),l(` kick start Run production build`),l(``),l(`Generators:`),l(` kick g module <name> Full DDD module (controller, DTOs, use-cases, repo)`),l(` kick g scaffold <n> <f..> CRUD module from field definitions`),l(` kick g controller <name> Standalone controller`),l(` kick g service <name> @Service() class`),l(` kick g middleware <name> Express middleware`),l(` kick g guard <name> Route guard (auth, roles, etc.)`),l(` kick g adapter <name> AppAdapter with lifecycle hooks`),l(` kick g dto <name> Zod DTO schema`),l(` kick g config Generate kick.config.ts`),l(``),l(`Add packages:`),l(` kick add <pkg> Install a KickJS package + peers`),l(` kick add --list Show all available packages`),l(``),l(`Available: auth, swagger, drizzle, prisma, ws, queue, devtools, mcp, testing`),l(``)}const St={GET:k.green,POST:k.cyan,PUT:k.yellow,PATCH:k.magenta,DELETE:k.red};function Ct(e){return(St[e]??k.dim)(e.padEnd(7))}function wt(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 Tt(e){O.intro(k.bgCyan(k.black(` ${e} `)))}function F(e){O.outro(e)}function Et(e){O.isCancel(e)&&(O.cancel(`Operation cancelled.`),process.exit(0))}async function Dt(e){let t=await O.text(e);return Et(t),t}async function Ot(e){let t=await O.select(e);return Et(t),t}async function kt(e){let t=await O.multiselect(e);return Et(t),t}async function I(e){let t=await O.confirm(e);return Et(t),t}function At(){return O.spinner()}const L=O.log,jt={kickjs:{pkg:`@forinda/kickjs`,peers:[`express`],description:`Unified framework: DI, decorators, routing, middleware`,core:!0},vite:{pkg:`@forinda/kickjs-vite`,peers:[`vite`],description:`Vite plugin: dev server, HMR, module discovery`,dev:!0,core:!0},cli:{pkg:`@forinda/kickjs-cli`,peers:[],description:`CLI tool and code generators`,dev:!0,core:!0},zod:{pkg:`zod`,peers:[],description:`Zod schema validation (env, DTOs, OpenAPI) — wrap with fromZod()`},valibot:{pkg:`valibot`,peers:[],description:`Valibot schema validation — wrap with fromValibot()`},yup:{pkg:`yup`,peers:[],description:`Yup schema validation — wrap with fromYup()`},swagger:{pkg:`@forinda/kickjs-swagger`,peers:[],description:`OpenAPI spec + Swagger UI + ReDoc`},db:{pkg:`@forinda/kickjs-db`,peers:[],description:`kick/db core — schema DSL, migrations, KickDbClient, customType`},pg:{pkg:`@forinda/kickjs-db`,peers:[`pg`],description:`kick/db + PostgreSQL driver (use @forinda/kickjs-db/pg)`},sqlite:{pkg:`@forinda/kickjs-db`,peers:[`better-sqlite3`],description:`kick/db + SQLite driver (use @forinda/kickjs-db/sqlite)`},mysql:{pkg:`@forinda/kickjs-db`,peers:[`mysql2`],description:`kick/db + MySQL driver (use @forinda/kickjs-db/mysql)`},drizzle:{pkg:`@forinda/kickjs-drizzle`,peers:[`drizzle-orm`],description:`Drizzle ORM adapter + query builder`},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},queue:{pkg:`@forinda/kickjs-queue`,peers:[],description:`Queue adapter (BullMQ/RabbitMQ/Kafka)`},"queue:bullmq":{pkg:`@forinda/kickjs-queue`,peers:[`bullmq`,`ioredis`],description:`Queue with BullMQ + Redis`},"queue:rabbitmq":{pkg:`@forinda/kickjs-queue`,peers:[`amqplib`],description:`Queue with RabbitMQ`},"queue:kafka":{pkg:`@forinda/kickjs-queue`,peers:[`kafkajs`],description:`Queue with Kafka`},"queue:redis-pubsub":{pkg:`@forinda/kickjs-queue`,peers:[`ioredis`],description:`Lightweight pub/sub via Redis (no persistence)`},mcp:{pkg:`@forinda/kickjs-mcp`,peers:[`@modelcontextprotocol/sdk`],description:`Model Context Protocol server — expose @Controller endpoints as AI tools`},testing:{pkg:`@forinda/kickjs-testing`,peers:[],description:`Test utilities and TestModule builder`,dev:!0}};function Mt(e,t=process.cwd()){let n=t;for(;;){if(r(v(n,e)))return n;let t=f(n);if(t===n)return null;n=t}}function Nt(){return Mt(`pnpm-lock.yaml`)?`pnpm`:Mt(`yarn.lock`)?`yarn`:Mt(`bun.lockb`)||Mt(`bun.lock`)?`bun`:Mt(`package-lock.json`)?`npm`:null}function Pt(){let e=process.cwd();for(;e;){let t=v(e,`package.json`);if(r(t))try{let e=JSON.parse(a(t,`utf-8`)).packageManager;if(typeof e==`string`){let t=e.split(`@`)[0];if(Ce.includes(t))return t}}catch{}let n=f(e);if(n===e)return null;e=n}return null}async function Ft(e){if(e&&Ce.includes(e))return{pm:e,source:`flag`};let t=await M(process.cwd());if(t?.packageManager&&Ce.includes(t.packageManager))return{pm:t.packageManager,source:`config`};let n=Pt();if(n)return{pm:n,source:`package.json`};let r=Nt();return r?{pm:r,source:`lockfile`}:{pm:`npm`,source:`default`}}async function It(e){let{pm:t}=await Ft(e);return t}function Lt(e=!1){let t=Object.entries(jt),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(`
1251
1195
  Core packages (always installed by \`kick new\`):
1252
1196
  `);for(let e of r)console.log(a(e));if(e){console.log(`
1253
1197
  Optional packages (add as needed):
1254
1198
  `);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(`
1255
- Usage: kick add auth drizzle swagger`),console.log(` kick add queue:bullmq`),console.log()}function qt(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=>{Kt(!!e.all)})}function Jt(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){Kt(!!t.all);return}let{pm:n,source:r}=await Wt(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.
1256
- `),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{S(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{S(t,{stdio:`inherit`})}catch{console.log(`\n Installation failed. Run manually:\n ${t}\n`)}}console.log(` Done!
1257
- `)}})}const Yt=[{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 Xt(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(`-s, --schema <lib>`,`Schema library for env / DTOs: zod | valibot | yup (default: zod)`).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)=>{Pt(`KickJS — Create a new project`);let n=!!(t.yes||t.nonInteractive);e||=n?`my-api`:await It({message:`Project name`,placeholder:`my-api`,defaultValue:`my-api`});let i;if(e===`.`?(i=v(`.`),e=d(i)):i=v(t.directory||e),r(i)){let r=o(i);if(r.length>0){if(t.force)F.warn(`Clearing existing files in ${i}`);else if(n){F.warn(`Directory "${e}" is not empty. Pass --force to clear it.`),N(`Aborted.`);return}else{F.warn(`Directory "${e}" is not empty:`);let t=r.slice(0,5);for(let e of t)F.message(` - ${e}`);if(r.length>5&&F.message(` ... and ${r.length-5} more`),!await P({message:E.red(`Remove all existing files and proceed?`),initialValue:!1})){N(`Aborted.`);return}}for(let e of r)s(v(i,e),{recursive:!0,force:!0})}}let a=t.template;a||=n?`minimal`:await Lt({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 c=t.pm;c||=n?await Gt(void 0):await Lt({message:`Package manager`,options:[{value:`pnpm`,label:`pnpm`},{value:`npm`,label:`npm`},{value:`yarn`,label:`yarn`},{value:`bun`,label:`bun`}]});let l=t.repo;l||(n?l=`inmemory`:(l=await Lt({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`}]}),l===`custom`&&(l=await It({message:`Custom repository name`,defaultValue:`custom`}))));let u=t.schema;u||=n?`zod`:await Lt({message:`Schema library (env + DTO validation)`,options:[{value:`zod`,label:`Zod`,hint:`default — broad ecosystem`},{value:`valibot`,label:`Valibot`,hint:`smaller bundle`},{value:`yup`,label:`Yup`,hint:`classic API`}]}),[`zod`,`valibot`,`yup`].includes(u)||(F.warn(`Unknown --schema "${u}", falling back to zod.`),u=`zod`);let f;if(t.packages!==void 0){let e=t.packages.trim().toLowerCase();f=e===``||e===`none`||e===`false`?[]:t.packages.split(`,`).map(e=>e.trim()).filter(Boolean)}else f=n?[]:await Rt({message:`Select packages to include`,options:[...Yt],required:!1});let p;p=t.git===void 0?n?!0:await P({message:`Initialize git repository?`,initialValue:!0}):t.git;let m;m=t.install===void 0?n?!0:await P({message:`Install dependencies?`,initialValue:!0}):t.install,await At({name:e,directory:i,packageManager:c,initGit:p,installDeps:m,template:a,defaultRepo:l,packages:f,schemaLib:u}),N(`Done! Next steps: ${E.cyan(`cd ${e} && ${c} dev`)}`)})}function I(e){return e.replace(/[-_\s]+(.)?/g,(e,t)=>t?t.toUpperCase():``).replace(/^(.)/,e=>e.toUpperCase())}function L(e){let t=I(e);return t.charAt(0).toLowerCase()+t.slice(1)}function R(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}function z(e){return de.plural(e)}function Zt(e){return de.plural(e)}var Qt=D({findProjectRoot:()=>en});const $t=[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`,`kick.config.json`];function en(e=process.cwd()){let t=v(e),{root:n}=g(t),i=null,a=t;for(;;){for(let e of $t)if(r(v(a,e)))return a;if(i===null&&r(v(a,`package.json`))&&(i=a),a===n)break;let e=f(a);if(e===a)break;a=e}return i??t}function tn(e){return R(e).replace(/-/g,`_`)}function nn(e){let t=e.cwd??process.cwd(),n=e.projectRoot??en(t),r=e.pluralize??!0,i=I(e.name),a=L(e.name),o=R(e.name),s=tn(e.name),c={name:e.name,pascal:i,camel:a,kebab:o,snake:s,modulesDir:e.modulesDir??`src/modules`,cwd:t,projectRoot:n,args:e.args??[],flags:e.flags??{}};if(r){let e=z(o);c.pluralKebab=e,c.pluralPascal=I(e),c.pluralCamel=L(e)}return c}function rn(e,t){return v(e.cwd,t)}async function an(e){return import(x(e).href)}const on=new Map;async function sn(e){let t=on.get(e);if(t)return t;let n=cn(e);return on.set(e,n),n}async function cn(t){let n=v(t,`package.json`);if(!r(n))return{generators:[],loaded:[],failed:[]};let i=ln(JSON.parse(await C(n,`utf-8`))),a=e(v(t,`package.json`)),o=[],s=[],c=[];for(let e of i){let t;try{t=a.resolve(`${e}/package.json`)}catch{continue}let n;try{n=JSON.parse(await C(t,`utf-8`))}catch(t){c.push({source:e,reason:`failed to parse package.json: ${t}`});continue}if(!n.kickjs?.generators)continue;let i=n.kickjs.generators,l=v(f(t),i);if(!r(l)){c.push({source:e,reason:`kickjs.generators points to missing file: ${i}`});continue}let u;try{u=await an(l)}catch(t){c.push({source:e,reason:`failed to import manifest: ${t}`});continue}let d=u.default;if(!Array.isArray(d)){c.push({source:e,reason:`manifest's default export is not an array of GeneratorSpec`});continue}for(let t of d){if(!un(t)){c.push({source:e,reason:`manifest entry is not a valid GeneratorSpec (missing name/files)`});continue}o.push({source:e,spec:t})}s.push(e)}return{generators:o,loaded:s,failed:c}}function ln(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 un(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function dn(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return mn(r.spec,r.source,e,n);let i=pn(await sn(n),e.generatorName);return i?mn(i.spec,i.source,e,n):null}async function fn(e,t=[]){let n=await sn(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 pn(e,t){return e.generators.find(e=>e.spec.name===t)}async function mn(e,t,n,r){let i=nn({name:n.itemName,args:n.args,flags:n.flags,modulesDir:n.modulesDir,pluralize:n.pluralize,cwd:r,projectRoot:n.projectRoot}),a=await e.files(i),o=[];for(let e of a){let t=rn(i,e.path);await M(t,e.content),o.push(t)}return{files:o,source:t}}function B(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}const hn={inmemory:`in-memory`,drizzle:`Drizzle`,prisma:`Prisma`};function gn(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function _n(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).toLowerCase()}function vn(e){return hn[e]??gn(e)}function yn(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]??`${gn(n)}${e}Repository`,repoFile:i[n]??`${_n(n)}-${t}`}}function bn(e){return e??`define`}function xn(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,{repoClass:o,repoFile:s}=yn(t,n,i),c=bn(a),l=`/**
1258
- * ${t} Module
1259
- *
1260
- * Self-contained feature module following Domain-Driven Design (DDD).
1261
- * Registers dependencies in the DI container and declares HTTP routes.
1262
- *
1263
- * Structure:
1264
- * presentation/ — HTTP controllers (entry points)
1265
- * application/ — Use cases (orchestration) and DTOs (validation)
1266
- * domain/ — Entities, value objects, repository interfaces, domain services
1267
- * infrastructure/ — Repository implementations (currently ${vn(i)})
1268
- */`,u=`import { ${t.toUpperCase()}_REPOSITORY } from './domain/repositories/${n}.repository'
1269
- import { ${o} } from './infrastructure/repositories/${s}.repository'
1270
- import { ${t}Controller } from './presentation/${n}.controller'
1271
-
1272
- // Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container
1273
- import.meta.glob(
1274
- ['./domain/services/**/*.ts', './application/use-cases/**/*.ts', '!./**/*.test.ts'],
1275
- { eager: true },
1276
- )`,d=` /**
1277
- * Declare HTTP routes for this module. Return value shape:
1278
- *
1279
- * - \`path\` — URL prefix for this route set, mounted under
1280
- * \`/{apiPrefix}/v{version}{path}\`.
1281
- * - \`controller\` — Controller class. Used both for the route
1282
- * handler bindings and OpenAPI spec generation.
1283
- * - \`version\` — Optional. Overrides the app-wide API version
1284
- * for this route set only.
1285
- *
1286
- * Return an **array** to mount multiple route sets under the
1287
- * same module (e.g. side-by-side v1 + v2 controllers):
1288
- *
1289
- * return [
1290
- * { path: '/${r}', version: 1, controller: ${t}V1Controller },
1291
- * { path: '/${r}', version: 2, controller: ${t}V2Controller },
1292
- * ]
1293
- */`;return c===`class`?`${l}
1294
- import { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'
1295
- ${u}
1296
-
1297
- export class ${t}Module implements AppModule {
1298
- /**
1299
- * Register module dependencies in the DI container.
1300
- * Bind repository interface tokens to their implementations here.
1301
- * Currently wired to ${vn(i)}. To swap implementations, change the factory target.
1302
- */
1303
- register(container: Container): void {
1304
- container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
1305
- container.resolve(${o}),
1306
- )
1307
- }
1308
-
1309
- ${d.replace(/^ {4}/gm,` `).replace(/^ {6}/gm,` `)}
1310
- routes(): ModuleRoutes {
1311
- return {
1312
- path: '/${r}',
1313
- controller: ${t}Controller,
1314
- }
1315
- }
1316
- }
1317
- `:`${l}
1318
- import { defineModule } from '@forinda/kickjs'
1319
- ${u}
1320
-
1321
- export const ${t}Module = defineModule({
1322
- name: '${t}Module',
1323
- build: () => ({
1324
- /**
1325
- * Register module dependencies in the DI container.
1326
- * Bind repository interface tokens to their implementations here.
1327
- * Currently wired to ${vn(i)}. To swap implementations, change the factory target.
1328
- */
1329
- register(container) {
1330
- container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
1331
- container.resolve(${o}),
1332
- )
1333
- },
1334
-
1335
- ${d}
1336
- routes() {
1337
- return {
1338
- path: '/${r}',
1339
- controller: ${t}Controller,
1340
- }
1341
- },
1342
- }),
1343
- })
1344
- `}function Sn(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,{repoClass:o,repoFile:s}=yn(t,n,i),c=bn(a),l=`/**
1199
+ Usage: kick add auth drizzle swagger`),console.log(` kick add queue:bullmq`),console.log()}function Rt(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=>{Lt(!!e.all)})}function zt(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){Lt(!!t.all);return}let{pm:n,source:r}=await Ft(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=jt[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.
1200
+ `),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{C(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{C(t,{stdio:`inherit`})}catch{console.log(`\n Installation failed. Run manually:\n ${t}\n`)}}console.log(` Done!
1201
+ `)}})}const Bt=[{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 Vt(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 | minimal`).option(`-r, --repo <type>`,`Repository name (inmemory, or any DB name e.g. postgres)`).option(`-s, --schema <lib>`,`Schema library for env / DTOs: zod | valibot | yup (default: zod)`).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)=>{Tt(`KickJS — Create a new project`);let n=!!(t.yes||t.nonInteractive);e||=n?`my-api`:await Dt({message:`Project name`,placeholder:`my-api`,defaultValue:`my-api`});let i;if(e===`.`?(i=v(`.`),e=d(i)):i=v(t.directory||e),r(i)){let r=o(i);if(r.length>0){if(t.force)L.warn(`Clearing existing files in ${i}`);else if(n){L.warn(`Directory "${e}" is not empty. Pass --force to clear it.`),F(`Aborted.`);return}else{L.warn(`Directory "${e}" is not empty:`);let t=r.slice(0,5);for(let e of t)L.message(` - ${e}`);if(r.length>5&&L.message(` ... and ${r.length-5} more`),!await I({message:k.red(`Remove all existing files and proceed?`),initialValue:!1})){F(`Aborted.`);return}}for(let e of r)s(v(i,e),{recursive:!0,force:!0})}}let a=t.template;a||=n?`minimal`:await Ot({message:`Project template`,options:[{value:`rest`,label:`REST API`,hint:`Express + Swagger`},{value:`minimal`,label:`Minimal`,hint:`bare Express`}]});let c=t.pm;c||=n?await It(void 0):await Ot({message:`Package manager`,options:[{value:`pnpm`,label:`pnpm`},{value:`npm`,label:`npm`},{value:`yarn`,label:`yarn`},{value:`bun`,label:`bun`}]});let l=t.repo;l||=n?`inmemory`:await Dt({message:`Repository name`,placeholder:`inmemory (or a DB name, e.g. postgres)`,defaultValue:`inmemory`}),Ee(l);let u=t.schema;u||=n?`zod`:await Ot({message:`Schema library (env + DTO validation)`,options:[{value:`zod`,label:`Zod`,hint:`default — broad ecosystem`},{value:`valibot`,label:`Valibot`,hint:`smaller bundle`},{value:`yup`,label:`Yup`,hint:`classic API`}]}),[`zod`,`valibot`,`yup`].includes(u)||(L.warn(`Unknown --schema "${u}", falling back to zod.`),u=`zod`);let f;if(t.packages!==void 0){let e=t.packages.trim().toLowerCase();f=e===``||e===`none`||e===`false`?[]:t.packages.split(`,`).map(e=>e.trim()).filter(Boolean)}else f=n?[]:await kt({message:`Select packages to include`,options:[...Bt],required:!1});let p;p=t.git===void 0?n?!0:await I({message:`Initialize git repository?`,initialValue:!0}):t.git;let m;m=t.install===void 0?n?!0:await I({message:`Install dependencies?`,initialValue:!0}):t.install,await xt({name:e,directory:i,packageManager:c,initGit:p,installDeps:m,template:a,defaultRepo:l,packages:f,schemaLib:u}),F(`Done! Next steps: ${k.cyan(`cd ${e} && ${c} 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 ue.plural(e)}function Ht(e){return ue.plural(e)}var Ut=A({findProjectRoot:()=>Gt});const Wt=[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`,`kick.config.json`];function Gt(e=process.cwd()){let t=v(e),{root:n}=g(t),i=null,a=t;for(;;){for(let e of Wt)if(r(v(a,e)))return a;if(i===null&&r(v(a,`package.json`))&&(i=a),a===n)break;let e=f(a);if(e===a)break;a=e}return i??t}function Kt(e){return B(e).replace(/-/g,`_`)}function qt(e){let t=e.cwd??process.cwd(),n=e.projectRoot??Gt(t),r=e.pluralize??!0,i=R(e.name),a=z(e.name),o=B(e.name),s=Kt(e.name),c={name:e.name,pascal:i,camel:a,kebab:o,snake:s,modulesDir:e.modulesDir??`src/modules`,cwd:t,projectRoot:n,args:e.args??[],flags:e.flags??{}};if(r){let e=V(o);c.pluralKebab=e,c.pluralPascal=R(e),c.pluralCamel=z(e)}return c}function Jt(e,t){return v(e.cwd,t)}async function Yt(e){return import(x(e).href)}const Xt=new Map;async function Zt(e){let t=Xt.get(e);if(t)return t;let n=Qt(e);return Xt.set(e,n),n}async function Qt(t){let n=v(t,`package.json`);if(!r(n))return{generators:[],loaded:[],failed:[]};let i=$t(JSON.parse(await T(n,`utf-8`))),a=e(v(t,`package.json`)),o=[],s=[],c=[];for(let e of i){let t;try{t=a.resolve(`${e}/package.json`)}catch{continue}let n;try{n=JSON.parse(await T(t,`utf-8`))}catch(t){c.push({source:e,reason:`failed to parse package.json: ${t}`});continue}if(!n.kickjs?.generators)continue;let i=n.kickjs.generators,l=v(f(t),i);if(!r(l)){c.push({source:e,reason:`kickjs.generators points to missing file: ${i}`});continue}let u;try{u=await Yt(l)}catch(t){c.push({source:e,reason:`failed to import manifest: ${t}`});continue}let d=u.default;if(!Array.isArray(d)){c.push({source:e,reason:`manifest's default export is not an array of GeneratorSpec`});continue}for(let t of d){if(!en(t)){c.push({source:e,reason:`manifest entry is not a valid GeneratorSpec (missing name/files)`});continue}o.push({source:e,spec:t})}s.push(e)}return{generators:o,loaded:s,failed:c}}function $t(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 en(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function tn(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return an(r.spec,r.source,e,n);let i=rn(await Zt(n),e.generatorName);return i?an(i.spec,i.source,e,n):null}async function nn(e,t=[]){let n=await Zt(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 rn(e,t){return e.generators.find(e=>e.spec.name===t)}async function an(e,t,n,r){let i=qt({name:n.itemName,args:n.args,flags:n.flags,modulesDir:n.modulesDir,pluralize:n.pluralize,cwd:r,projectRoot:n.projectRoot}),a=await e.files(i),o=[];for(let e of a){let t=Jt(i,e.path);await P(t,e.content),o.push(t)}return{files:o,source:t}}function H(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function on(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function sn(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).toLowerCase()}function cn(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]??`${on(n)}${e}Repository`,repoFile:i[n]??`${sn(n)}-${t}`}}function ln(e){return e??`define`}function un(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,{repoClass:o,repoFile:s}=cn(t,n,i),c=ln(a),l=`/**
1345
1202
  * ${t} Module
1346
1203
  *
1347
1204
  * REST module with a flat folder structure.
@@ -1413,7 +1270,7 @@ ${d}
1413
1270
  },
1414
1271
  }),
1415
1272
  })
1416
- `}function Cn(e){let{pascal:t,kebab:n,plural:r=``,style:i}=e,a=bn(i),o=` /**
1273
+ `}function dn(e){let{pascal:t,kebab:n,plural:r=``,style:i}=e,a=ln(i),o=` /**
1417
1274
  * Declare HTTP routes. Return value shape:
1418
1275
  *
1419
1276
  * - \`path\` — URL prefix for this route set.
@@ -1453,70 +1310,7 @@ ${o}
1453
1310
  },
1454
1311
  }),
1455
1312
  })
1456
- `}function wn(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'
1457
- import { ApiTags } from '@forinda/kickjs-swagger'
1458
- import { Create${t}UseCase } from '../application/use-cases/create-${n}.use-case'
1459
- import { Get${t}UseCase } from '../application/use-cases/get-${n}.use-case'
1460
- import { List${i}UseCase } from '../application/use-cases/list-${r}.use-case'
1461
- import { Update${t}UseCase } from '../application/use-cases/update-${n}.use-case'
1462
- import { Delete${t}UseCase } from '../application/use-cases/delete-${n}.use-case'
1463
- import { create${t}Schema } from '../application/dtos/create-${n}.dto'
1464
- import { update${t}Schema } from '../application/dtos/update-${n}.dto'
1465
- import { ${t.toUpperCase()}_QUERY_CONFIG } from '../constants'
1466
-
1467
- // Each handler annotates its \`ctx\` with \`Ctx<KickRoutes.${t}Controller['<method>']>\`
1468
- // so \`ctx.params\`, \`ctx.body\`, and \`ctx.query\` are typed end-to-end.
1469
- // The \`KickRoutes\` namespace is generated by \`kick typegen\` (auto-run on
1470
- // \`kick dev\`) — see https://forinda.github.io/kick-js/guide/typegen.
1471
-
1472
- @Controller()
1473
- export class ${t}Controller {
1474
- @Autowired() private readonly create${t}UseCase!: Create${t}UseCase
1475
- @Autowired() private readonly get${t}UseCase!: Get${t}UseCase
1476
- @Autowired() private readonly list${i}UseCase!: List${i}UseCase
1477
- @Autowired() private readonly update${t}UseCase!: Update${t}UseCase
1478
- @Autowired() private readonly delete${t}UseCase!: Delete${t}UseCase
1479
-
1480
- @Get('/')
1481
- @ApiTags('${t}')
1482
- @ApiQueryParams(${t.toUpperCase()}_QUERY_CONFIG)
1483
- async list(ctx: Ctx<KickRoutes.${t}Controller['list']>) {
1484
- return ctx.paginate(
1485
- (parsed) => this.list${i}UseCase.execute(parsed),
1486
- ${t.toUpperCase()}_QUERY_CONFIG,
1487
- )
1488
- }
1489
-
1490
- @Get('/:id')
1491
- @ApiTags('${t}')
1492
- async getById(ctx: Ctx<KickRoutes.${t}Controller['getById']>) {
1493
- const result = await this.get${t}UseCase.execute(ctx.params.id)
1494
- if (!result) return ctx.notFound('${t} not found')
1495
- ctx.json(result)
1496
- }
1497
-
1498
- @Post('/', { body: create${t}Schema, name: 'Create${t}' })
1499
- @ApiTags('${t}')
1500
- async create(ctx: Ctx<KickRoutes.${t}Controller['create']>) {
1501
- const result = await this.create${t}UseCase.execute(ctx.body)
1502
- ctx.created(result)
1503
- }
1504
-
1505
- @Put('/:id', { body: update${t}Schema, name: 'Update${t}' })
1506
- @ApiTags('${t}')
1507
- async update(ctx: Ctx<KickRoutes.${t}Controller['update']>) {
1508
- const result = await this.update${t}UseCase.execute(ctx.params.id, ctx.body)
1509
- ctx.json(result)
1510
- }
1511
-
1512
- @Delete('/:id')
1513
- @ApiTags('${t}')
1514
- async remove(ctx: Ctx<KickRoutes.${t}Controller['remove']>) {
1515
- await this.delete${t}UseCase.execute(ctx.params.id)
1516
- ctx.noContent()
1517
- }
1518
- }
1519
- `}function Tn(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'
1313
+ `}function fn(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'
1520
1314
  import { ApiTags } from '@forinda/kickjs-swagger'
1521
1315
  import { ${t}Service } from './${n}.service'
1522
1316
  import { create${t}Schema } from './dtos/create-${n}.dto'
@@ -1571,14 +1365,7 @@ export class ${t}Controller {
1571
1365
  ctx.noContent()
1572
1366
  }
1573
1367
  }
1574
- `}function En(e){let{pascal:t}=e;return`import type { QueryParamsConfig } from '@forinda/kickjs'
1575
-
1576
- export const ${t.toUpperCase()}_QUERY_CONFIG: QueryParamsConfig = {
1577
- filterable: ['name'],
1578
- sortable: ['name', 'createdAt'],
1579
- searchable: ['name'],
1580
- }
1581
- `}function Dn(e){let{pascal:t}=e;return`import { z } from 'zod'
1368
+ `}function pn(e){let{pascal:t}=e;return`import { z } from 'zod'
1582
1369
 
1583
1370
  /**
1584
1371
  * Create ${t} DTO — Zod schema for validating POST request bodies.
@@ -1594,98 +1381,20 @@ export const create${t}Schema = z.object({
1594
1381
  })
1595
1382
 
1596
1383
  export type Create${t}DTO = z.infer<typeof create${t}Schema>
1597
- `}function On(e){let{pascal:t}=e;return`import { z } from 'zod'
1384
+ `}function mn(e){let{pascal:t}=e;return`import { z } from 'zod'
1598
1385
 
1599
1386
  export const update${t}Schema = z.object({
1600
1387
  name: z.string().min(1).max(200).optional(),
1601
1388
  })
1602
1389
 
1603
1390
  export type Update${t}DTO = z.infer<typeof update${t}Schema>
1604
- `}function kn(e){let{pascal:t}=e;return`export interface ${t}ResponseDTO {
1391
+ `}function hn(e){let{pascal:t}=e;return`export interface ${t}ResponseDTO {
1605
1392
  id: string
1606
1393
  name: string
1607
1394
  createdAt: string
1608
1395
  updatedAt: string
1609
1396
  }
1610
- `}function An(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return[{file:`create-${n}.use-case.ts`,content:`/**
1611
- * Create ${t} Use Case
1612
- *
1613
- * Application layer — orchestrates a single business operation.
1614
- * Use cases are thin: validate input (via DTO), call domain/repo, return response.
1615
- * Keep business rules in the domain service, not here.
1616
- */
1617
- import { Service, Inject } from '@forinda/kickjs'
1618
- import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../../domain/repositories/${n}.repository'
1619
- import type { Create${t}DTO } from '../dtos/create-${n}.dto'
1620
- import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
1621
-
1622
- @Service()
1623
- export class Create${t}UseCase {
1624
- constructor(
1625
- @Inject(${t.toUpperCase()}_REPOSITORY) private readonly repo: I${t}Repository,
1626
- ) {}
1627
-
1628
- async execute(dto: Create${t}DTO): Promise<${t}ResponseDTO> {
1629
- return this.repo.create(dto)
1630
- }
1631
- }
1632
- `},{file:`get-${n}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
1633
- import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../../domain/repositories/${n}.repository'
1634
- import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
1635
-
1636
- @Service()
1637
- export class Get${t}UseCase {
1638
- constructor(
1639
- @Inject(${t.toUpperCase()}_REPOSITORY) private readonly repo: I${t}Repository,
1640
- ) {}
1641
-
1642
- async execute(id: string): Promise<${t}ResponseDTO | null> {
1643
- return this.repo.findById(id)
1644
- }
1645
- }
1646
- `},{file:`list-${r}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
1647
- import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../../domain/repositories/${n}.repository'
1648
- import type { ParsedQuery } from '@forinda/kickjs'
1649
-
1650
- @Service()
1651
- export class List${i}UseCase {
1652
- constructor(
1653
- @Inject(${t.toUpperCase()}_REPOSITORY) private readonly repo: I${t}Repository,
1654
- ) {}
1655
-
1656
- async execute(parsed: ParsedQuery) {
1657
- return this.repo.findPaginated(parsed)
1658
- }
1659
- }
1660
- `},{file:`update-${n}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
1661
- import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../../domain/repositories/${n}.repository'
1662
- import type { Update${t}DTO } from '../dtos/update-${n}.dto'
1663
- import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
1664
-
1665
- @Service()
1666
- export class Update${t}UseCase {
1667
- constructor(
1668
- @Inject(${t.toUpperCase()}_REPOSITORY) private readonly repo: I${t}Repository,
1669
- ) {}
1670
-
1671
- async execute(id: string, dto: Update${t}DTO): Promise<${t}ResponseDTO> {
1672
- return this.repo.update(id, dto)
1673
- }
1674
- }
1675
- `},{file:`delete-${n}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
1676
- import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../../domain/repositories/${n}.repository'
1677
-
1678
- @Service()
1679
- export class Delete${t}UseCase {
1680
- constructor(
1681
- @Inject(${t.toUpperCase()}_REPOSITORY) private readonly repo: I${t}Repository,
1682
- ) {}
1683
-
1684
- async execute(id: string): Promise<void> {
1685
- await this.repo.delete(id)
1686
- }
1687
- }
1688
- `}]}function jn(e){let{pascal:t,kebab:n,dtoPrefix:r=`../../application/dtos`,tokenScope:i=`app`}=e;return`/**
1397
+ `}function gn(e){let{pascal:t,kebab:n,dtoPrefix:r=`../../application/dtos`,tokenScope:i=`app`}=e;return`/**
1689
1398
  * ${t} Repository Interface
1690
1399
  *
1691
1400
  * Defines the contract for data access.
@@ -1720,7 +1429,7 @@ export interface I${t}Repository {
1720
1429
  * adopters must NOT use the reserved \`'kick/'\` namespace.
1721
1430
  */
1722
1431
  export const ${t.toUpperCase()}_REPOSITORY = createToken<I${t}Repository>('${i}/${t}/repository')
1723
- `}function V(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e;return`/**
1432
+ `}function _n(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e;return`/**
1724
1433
  * In-Memory ${t} Repository
1725
1434
  *
1726
1435
  * Implements the repository interface using a Map.
@@ -1759,7 +1468,7 @@ export class InMemory${t}Repository implements I${t}Repository {
1759
1468
  const now = new Date().toISOString()
1760
1469
  const entity: ${t}ResponseDTO = {
1761
1470
  id: randomUUID(),
1762
- name: dto.name,
1471
+ ...dto,
1763
1472
  createdAt: now,
1764
1473
  updatedAt: now,
1765
1474
  }
@@ -1780,7 +1489,7 @@ export class InMemory${t}Repository implements I${t}Repository {
1780
1489
  this.store.delete(id)
1781
1490
  }
1782
1491
  }
1783
- `}function Mn(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`/**
1492
+ `}function vn(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`/**
1784
1493
  * ${o} ${t} Repository
1785
1494
  *
1786
1495
  * Stub implementation for a custom '${r}' repository.
@@ -1826,7 +1535,7 @@ export class ${o}${t}Repository implements I${t}Repository {
1826
1535
  const now = new Date().toISOString()
1827
1536
  const entity: ${t}ResponseDTO = {
1828
1537
  id: randomUUID(),
1829
- name: dto.name,
1538
+ ...dto,
1830
1539
  createdAt: now,
1831
1540
  updatedAt: now,
1832
1541
  }
@@ -1849,133 +1558,7 @@ export class ${o}${t}Repository implements I${t}Repository {
1849
1558
  this.store.delete(id)
1850
1559
  }
1851
1560
  }
1852
- `}function Nn(e){let{pascal:t,kebab:n}=e;return`/**
1853
- * ${t} Domain Service
1854
- *
1855
- * Domain layer — contains business rules that don't belong to a single entity.
1856
- * Use this for cross-entity logic, validation rules, and domain invariants.
1857
- * Keep it free of HTTP/framework concerns.
1858
- */
1859
- import { Service, Inject, HttpException } from '@forinda/kickjs'
1860
- import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../repositories/${n}.repository'
1861
-
1862
- @Service()
1863
- export class ${t}DomainService {
1864
- constructor(
1865
- @Inject(${t.toUpperCase()}_REPOSITORY) private readonly repo: I${t}Repository,
1866
- ) {}
1867
-
1868
- async ensureExists(id: string): Promise<void> {
1869
- const entity = await this.repo.findById(id)
1870
- if (!entity) {
1871
- throw HttpException.notFound('${t} not found')
1872
- }
1873
- }
1874
- }
1875
- `}function Pn(e){let{pascal:t,kebab:n}=e;return`/**
1876
- * ${t} Entity
1877
- *
1878
- * Domain layer — the core business object.
1879
- * Uses a private constructor with static factory methods (create, reconstitute)
1880
- * to enforce invariants. Properties are accessed via getters to maintain encapsulation.
1881
- *
1882
- * Patterns used:
1883
- * - Private constructor: prevents direct instantiation
1884
- * - create(): factory for new entities (generates ID, sets timestamps)
1885
- * - reconstitute(): factory for rebuilding from persistence (no side effects)
1886
- * - changeName(): mutation method that enforces business rules
1887
- */
1888
- import { ${t}Id } from '../value-objects/${n}-id.vo'
1889
-
1890
- interface ${t}Props {
1891
- id: ${t}Id
1892
- name: string
1893
- createdAt: Date
1894
- updatedAt: Date
1895
- }
1896
-
1897
- export class ${t} {
1898
- private constructor(private props: ${t}Props) {}
1899
-
1900
- static create(params: { name: string }): ${t} {
1901
- const now = new Date()
1902
- return new ${t}({
1903
- id: ${t}Id.create(),
1904
- name: params.name,
1905
- createdAt: now,
1906
- updatedAt: now,
1907
- })
1908
- }
1909
-
1910
- static reconstitute(props: ${t}Props): ${t} {
1911
- return new ${t}(props)
1912
- }
1913
-
1914
- get id(): ${t}Id {
1915
- return this.props.id
1916
- }
1917
- get name(): string {
1918
- return this.props.name
1919
- }
1920
- get createdAt(): Date {
1921
- return this.props.createdAt
1922
- }
1923
- get updatedAt(): Date {
1924
- return this.props.updatedAt
1925
- }
1926
-
1927
- changeName(name: string): void {
1928
- if (!name || name.trim().length === 0) {
1929
- throw new Error('Name cannot be empty')
1930
- }
1931
- this.props.name = name.trim()
1932
- this.props.updatedAt = new Date()
1933
- }
1934
-
1935
- toJSON() {
1936
- return {
1937
- id: this.props.id.toString(),
1938
- name: this.props.name,
1939
- createdAt: this.props.createdAt.toISOString(),
1940
- updatedAt: this.props.updatedAt.toISOString(),
1941
- }
1942
- }
1943
- }
1944
- `}function Fn(e){let{pascal:t}=e;return`/**
1945
- * ${t} ID Value Object
1946
- *
1947
- * Domain layer — wraps a primitive ID with type safety and validation.
1948
- * Value objects are immutable and compared by value, not reference.
1949
- *
1950
- * ${t}Id.create() — generate a new UUID
1951
- * ${t}Id.from(id) — wrap an existing ID string (validates non-empty)
1952
- * id.equals(other) — compare two IDs by value
1953
- */
1954
- import { randomUUID } from 'node:crypto'
1955
-
1956
- export class ${t}Id {
1957
- private constructor(private readonly value: string) {}
1958
-
1959
- static create(): ${t}Id {
1960
- return new ${t}Id(randomUUID())
1961
- }
1962
-
1963
- static from(id: string): ${t}Id {
1964
- if (!id || id.trim().length === 0) {
1965
- throw new Error('${t}Id cannot be empty')
1966
- }
1967
- return new ${t}Id(id)
1968
- }
1969
-
1970
- toString(): string {
1971
- return this.value
1972
- }
1973
-
1974
- equals(other: ${t}Id): boolean {
1975
- return this.value === other.value
1976
- }
1977
- }
1978
- `}function In(e){let{pascal:t,kebab:n,plural:r=``}=e;return`import { describe, it, expect, beforeEach } from 'vitest'
1561
+ `}function yn(e){let{pascal:t,kebab:n,plural:r=``}=e;return`import { describe, it, expect, beforeEach } from 'vitest'
1979
1562
  import { Container } from '@forinda/kickjs'
1980
1563
 
1981
1564
  describe('${t}Controller', () => {
@@ -2027,7 +1610,7 @@ describe('${t}Controller', () => {
2027
1610
  })
2028
1611
  })
2029
1612
  })
2030
- `}function Ln(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'
1613
+ `}function bn(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'
2031
1614
  import { InMemory${t}Repository } from '${i}'
2032
1615
 
2033
1616
  describe('InMemory${t}Repository', () => {
@@ -2089,7 +1672,7 @@ describe('InMemory${t}Repository', () => {
2089
1672
  expect(found).toBeNull()
2090
1673
  })
2091
1674
  })
2092
- `}function Rn(e){let{pascal:t,kebab:n}=e;return`import { Service, Inject, HttpException } from '@forinda/kickjs'
1675
+ `}function xn(e){let{pascal:t,kebab:n}=e;return`import { Service, Inject, HttpException } from '@forinda/kickjs'
2093
1676
  import type { ParsedQuery } from '@forinda/kickjs'
2094
1677
  import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from './${n}.repository'
2095
1678
  import type { ${t}ResponseDTO } from './dtos/${n}-response.dto'
@@ -2126,485 +1709,17 @@ export class ${t}Service {
2126
1709
  await this.repo.delete(id)
2127
1710
  }
2128
1711
  }
2129
- `}function zn(e){let{pascal:t}=e;return`import type { QueryFieldConfig } from '@forinda/kickjs'
1712
+ `}function Sn(e){let{pascal:t}=e;return`import type { QueryFieldConfig } from '@forinda/kickjs'
2130
1713
 
2131
1714
  export const ${t.toUpperCase()}_QUERY_CONFIG: QueryFieldConfig = {
2132
1715
  filterable: ['name'],
2133
1716
  sortable: ['name', 'createdAt'],
2134
1717
  searchable: ['name'],
2135
1718
  }
2136
- `}function Bn(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=`/**
2137
- * ${t} Module — CQRS Pattern
2138
- *
2139
- * Separates read (queries) and write (commands) operations.
2140
- * Events are emitted after state changes and can be handled via
2141
- * WebSocket broadcasts, queue jobs, or ETL pipelines.
2142
- *
2143
- * Structure:
2144
- * commands/ — Write operations (create, update, delete)
2145
- * queries/ — Read operations (get, list)
2146
- * events/ — Domain events + handlers (WS broadcast, queue dispatch)
2147
- * dtos/ — Request/response schemas
2148
- */`,f=`import { ${t.toUpperCase()}_REPOSITORY } from './${n}.repository'
2149
- import { ${c} } from './${l}.repository'
2150
- import { ${t}Controller } from './${n}.controller'
1719
+ `}async function Cn(e){let{pascal:t,kebab:n,plural:r,style:i,write:a}=e;await a(`${n}.module.ts`,dn({pascal:t,kebab:n,plural:r,style:i})),await a(`${n}.controller.ts`,`import { Controller, Get, type Ctx } from '@forinda/kickjs'
2151
1720
 
2152
- // Eagerly load decorated classes
2153
- import.meta.glob(
2154
- [
2155
- './commands/**/*.ts',
2156
- './queries/**/*.ts',
2157
- './events/**/*.ts',
2158
- '!./**/*.test.ts',
2159
- ],
2160
- { eager: true },
2161
- )`,p=` /**
2162
- * Declare HTTP routes for this CQRS module. Return value shape:
2163
- *
2164
- * - \`path\` — URL prefix for this route set.
2165
- * - \`controller\` — Controller class (also drives OpenAPI).
2166
- * - \`version\` — Optional. Overrides the app-wide API version.
2167
- *
2168
- * Return an array to mount multiple route sets:
2169
- *
2170
- * return [
2171
- * { path: '/${r}', version: 1, controller: ${t}V1Controller },
2172
- * { path: '/${r}', version: 2, controller: ${t}V2Controller },
2173
- * ]
2174
- */`;return u===`class`?`${d}
2175
- import { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'
2176
- ${f}
2177
-
2178
- export class ${t}Module implements AppModule {
2179
- register(container: Container): void {
2180
- container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
2181
- container.resolve(${c}),
2182
- )
2183
- }
2184
-
2185
- ${p.replace(/^ {4}/gm,` `).replace(/^ {6}/gm,` `)}
2186
- routes(): ModuleRoutes {
2187
- return {
2188
- path: '/${r}',
2189
- controller: ${t}Controller,
2190
- }
2191
- }
2192
- }
2193
- `:`${d}
2194
- import { defineModule } from '@forinda/kickjs'
2195
- ${f}
2196
-
2197
- export const ${t}Module = defineModule({
2198
- name: '${t}Module',
2199
- build: () => ({
2200
- register(container) {
2201
- container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
2202
- container.resolve(${c}),
2203
- )
2204
- },
2205
-
2206
- ${p}
2207
- routes() {
2208
- return {
2209
- path: '/${r}',
2210
- controller: ${t}Controller,
2211
- }
2212
- },
2213
- }),
2214
- })
2215
- `}function Vn(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'
2216
- import { ApiTags } from '@forinda/kickjs-swagger'
2217
- import { Create${t}Command } from './commands/create-${n}.command'
2218
- import { Update${t}Command } from './commands/update-${n}.command'
2219
- import { Delete${t}Command } from './commands/delete-${n}.command'
2220
- import { Get${t}Query } from './queries/get-${n}.query'
2221
- import { List${i}Query } from './queries/list-${r}.query'
2222
- import { create${t}Schema } from './dtos/create-${n}.dto'
2223
- import { update${t}Schema } from './dtos/update-${n}.dto'
2224
- import { ${t.toUpperCase()}_QUERY_CONFIG } from './${n}.constants'
2225
-
2226
- // Each handler annotates its \`ctx\` with \`Ctx<KickRoutes.${t}Controller['<method>']>\`
2227
- // so \`ctx.params\`, \`ctx.body\`, and \`ctx.query\` are typed end-to-end.
2228
- // The \`KickRoutes\` namespace is generated by \`kick typegen\` (auto-run on
2229
- // \`kick dev\`) — see https://forinda.github.io/kick-js/guide/typegen.
2230
-
2231
- @Controller()
2232
- export class ${t}Controller {
2233
- @Autowired() private readonly create${t}Command!: Create${t}Command
2234
- @Autowired() private readonly update${t}Command!: Update${t}Command
2235
- @Autowired() private readonly delete${t}Command!: Delete${t}Command
2236
- @Autowired() private readonly get${t}Query!: Get${t}Query
2237
- @Autowired() private readonly list${i}Query!: List${i}Query
2238
-
2239
- @Get('/')
2240
- @ApiTags('${t}')
2241
- @ApiQueryParams(${t.toUpperCase()}_QUERY_CONFIG)
2242
- async list(ctx: Ctx<KickRoutes.${t}Controller['list']>) {
2243
- return ctx.paginate(
2244
- (parsed) => this.list${i}Query.execute(parsed),
2245
- ${t.toUpperCase()}_QUERY_CONFIG,
2246
- )
2247
- }
2248
-
2249
- @Get('/:id')
2250
- @ApiTags('${t}')
2251
- async getById(ctx: Ctx<KickRoutes.${t}Controller['getById']>) {
2252
- const result = await this.get${t}Query.execute(ctx.params.id)
2253
- if (!result) return ctx.notFound('${t} not found')
2254
- ctx.json(result)
2255
- }
2256
-
2257
- @Post('/', { body: create${t}Schema, name: 'Create${t}' })
2258
- @ApiTags('${t}')
2259
- async create(ctx: Ctx<KickRoutes.${t}Controller['create']>) {
2260
- const result = await this.create${t}Command.execute(ctx.body)
2261
- ctx.created(result)
2262
- }
2263
-
2264
- @Put('/:id', { body: update${t}Schema, name: 'Update${t}' })
2265
- @ApiTags('${t}')
2266
- async update(ctx: Ctx<KickRoutes.${t}Controller['update']>) {
2267
- const result = await this.update${t}Command.execute(ctx.params.id, ctx.body)
2268
- ctx.json(result)
2269
- }
2270
-
2271
- @Delete('/:id')
2272
- @ApiTags('${t}')
2273
- async remove(ctx: Ctx<KickRoutes.${t}Controller['remove']>) {
2274
- await this.delete${t}Command.execute(ctx.params.id)
2275
- ctx.noContent()
2276
- }
2277
- }
2278
- `}function Hn(e){let{pascal:t,kebab:n}=e;return[{file:`create-${n}.command.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
2279
- import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../${n}.repository'
2280
- import type { Create${t}DTO } from '../dtos/create-${n}.dto'
2281
- import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
2282
- import { ${t}Events } from '../events/${n}.events'
2283
-
2284
- @Service()
2285
- export class Create${t}Command {
2286
- constructor(
2287
- @Inject(${t.toUpperCase()}_REPOSITORY) private readonly repo: I${t}Repository,
2288
- @Inject(${t}Events) private readonly events: ${t}Events,
2289
- ) {}
2290
-
2291
- async execute(dto: Create${t}DTO): Promise<${t}ResponseDTO> {
2292
- const result = await this.repo.create(dto)
2293
- this.events.emit('${n}.created', result)
2294
- return result
2295
- }
2296
- }
2297
- `},{file:`update-${n}.command.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
2298
- import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../${n}.repository'
2299
- import type { Update${t}DTO } from '../dtos/update-${n}.dto'
2300
- import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
2301
- import { ${t}Events } from '../events/${n}.events'
2302
-
2303
- @Service()
2304
- export class Update${t}Command {
2305
- constructor(
2306
- @Inject(${t.toUpperCase()}_REPOSITORY) private readonly repo: I${t}Repository,
2307
- @Inject(${t}Events) private readonly events: ${t}Events,
2308
- ) {}
2309
-
2310
- async execute(id: string, dto: Update${t}DTO): Promise<${t}ResponseDTO> {
2311
- const result = await this.repo.update(id, dto)
2312
- this.events.emit('${n}.updated', result)
2313
- return result
2314
- }
2315
- }
2316
- `},{file:`delete-${n}.command.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
2317
- import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../${n}.repository'
2318
- import { ${t}Events } from '../events/${n}.events'
2319
-
2320
- @Service()
2321
- export class Delete${t}Command {
2322
- constructor(
2323
- @Inject(${t.toUpperCase()}_REPOSITORY) private readonly repo: I${t}Repository,
2324
- @Inject(${t}Events) private readonly events: ${t}Events,
2325
- ) {}
2326
-
2327
- async execute(id: string): Promise<void> {
2328
- await this.repo.delete(id)
2329
- this.events.emit('${n}.deleted', { id })
2330
- }
2331
- }
2332
- `}]}function Un(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return[{file:`get-${n}.query.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
2333
- import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../${n}.repository'
2334
- import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
2335
-
2336
- @Service()
2337
- export class Get${t}Query {
2338
- constructor(
2339
- @Inject(${t.toUpperCase()}_REPOSITORY) private readonly repo: I${t}Repository,
2340
- ) {}
2341
-
2342
- async execute(id: string): Promise<${t}ResponseDTO | null> {
2343
- return this.repo.findById(id)
2344
- }
2345
- }
2346
- `},{file:`list-${r}.query.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
2347
- import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../${n}.repository'
2348
- import type { ParsedQuery } from '@forinda/kickjs'
2349
-
2350
- @Service()
2351
- export class List${i}Query {
2352
- constructor(
2353
- @Inject(${t.toUpperCase()}_REPOSITORY) private readonly repo: I${t}Repository,
2354
- ) {}
2355
-
2356
- async execute(parsed: ParsedQuery) {
2357
- return this.repo.findPaginated(parsed)
2358
- }
2359
- }
2360
- `}]}function Wn(e){let{pascal:t,kebab:n}=e;return[{file:`${n}.events.ts`,content:`import { Service } from '@forinda/kickjs'
2361
- import { EventEmitter } from 'node:events'
2362
- import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
2363
-
2364
- /**
2365
- * ${t} domain event types.
2366
- *
2367
- * These events are emitted by commands after state changes.
2368
- * Subscribe to them in event handlers for side effects:
2369
- * - WebSocket broadcasts (real-time UI updates)
2370
- * - Queue jobs (async processing, ETL pipelines)
2371
- * - Audit logging
2372
- * - Cache invalidation
2373
- */
2374
- export interface ${t}EventMap {
2375
- '${n}.created': ${t}ResponseDTO
2376
- '${n}.updated': ${t}ResponseDTO
2377
- '${n}.deleted': { id: string }
2378
- }
2379
-
2380
- @Service()
2381
- export class ${t}Events {
2382
- private emitter = new EventEmitter()
2383
-
2384
- emit<K extends keyof ${t}EventMap>(event: K, data: ${t}EventMap[K]): void {
2385
- this.emitter.emit(event, data)
2386
- }
2387
-
2388
- on<K extends keyof ${t}EventMap>(event: K, handler: (data: ${t}EventMap[K]) => void): void {
2389
- this.emitter.on(event, handler)
2390
- }
2391
-
2392
- off<K extends keyof ${t}EventMap>(event: K, handler: (data: ${t}EventMap[K]) => void): void {
2393
- this.emitter.off(event, handler)
2394
- }
2395
- }
2396
- `},{file:`on-${n}-change.handler.ts`,content:`import { Service, Autowired } from '@forinda/kickjs'
2397
- import { ${t}Events } from './${n}.events'
2398
-
2399
- /**
2400
- * ${t} Change Event Handler
2401
- *
2402
- * Reacts to domain events emitted by commands.
2403
- * Wire up side effects here:
2404
- *
2405
- * 1. WebSocket broadcast — notify connected clients in real-time
2406
- * import { WsGateway } from '@forinda/kickjs-ws'
2407
- * this.ws.broadcast('${n}-channel', { event, data })
2408
- *
2409
- * 2. Queue dispatch — offload heavy processing to background workers
2410
- * import { QueueService } from '@forinda/kickjs-queue'
2411
- * this.queue.add('${n}-etl', { action: event, payload: data })
2412
- *
2413
- * 3. ETL pipeline — transform and load data to external systems
2414
- * await this.etlPipeline.process(data)
2415
- */
2416
- @Service()
2417
- export class On${t}ChangeHandler {
2418
- @Autowired() private events!: ${t}Events
2419
-
2420
- // Uncomment to inject WebSocket and Queue services:
2421
- // @Autowired() private ws!: WsGateway
2422
- // @Autowired() private queue!: QueueService
2423
-
2424
- onInit(): void {
2425
- this.events.on('${n}.created', (data) => {
2426
- console.log('[${t}] Created:', data.id)
2427
- // TODO: Broadcast via WebSocket
2428
- // this.ws.broadcast('${n}-channel', { event: '${n}.created', data })
2429
- // TODO: Dispatch to queue for async processing / ETL
2430
- // this.queue.add('${n}-etl', { action: 'create', payload: data })
2431
- })
2432
-
2433
- this.events.on('${n}.updated', (data) => {
2434
- console.log('[${t}] Updated:', data.id)
2435
- // TODO: Broadcast via WebSocket
2436
- // this.ws.broadcast('${n}-channel', { event: '${n}.updated', data })
2437
- })
2438
-
2439
- this.events.on('${n}.deleted', (data) => {
2440
- console.log('[${t}] Deleted:', data.id)
2441
- // TODO: Broadcast via WebSocket
2442
- // this.ws.broadcast('${n}-channel', { event: '${n}.deleted', data })
2443
- })
2444
- }
2445
- }
2446
- `}]}function Gn(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e;return`/**
2447
- * Drizzle ${t} Repository
2448
- *
2449
- * Implements the repository interface using Drizzle ORM.
2450
- * Uses buildFromColumns() with Column objects for type-safe query building.
2451
- *
2452
- * TODO: Update the schema import to match your Drizzle schema file.
2453
- * TODO: Replace DRIZZLE_DB injection token with your actual database token.
2454
- *
2455
- * @Repository() registers this class in the DI container as a singleton.
2456
- */
2457
- import { eq, ne, gt, gte, lt, lte, ilike, inArray, between, and, or, asc, desc, count, sql } from 'drizzle-orm'
2458
- import { Repository, HttpException, Inject } from '@forinda/kickjs'
2459
- import { DRIZZLE_DB, DrizzleQueryAdapter } from '@forinda/kickjs-drizzle'
2460
- import type { ParsedQuery } from '@forinda/kickjs'
2461
- import type { I${t}Repository } from '${r}/${n}.repository'
2462
- import type { ${t}ResponseDTO } from '${i}/${n}-response.dto'
2463
- import type { Create${t}DTO } from '${i}/create-${n}.dto'
2464
- import type { Update${t}DTO } from '${i}/update-${n}.dto'
2465
- import { ${t.toUpperCase()}_QUERY_CONFIG } from '../../constants'
2466
-
2467
- // TODO: Import your Drizzle schema table — e.g.:
2468
- // import { ${n}s } from '@/db/schema'
2469
-
2470
- const queryAdapter = new DrizzleQueryAdapter({
2471
- eq, ne, gt, gte, lt, lte, ilike, inArray, between, and, or, asc, desc,
2472
- })
2473
-
2474
- @Repository()
2475
- export class Drizzle${t}Repository implements I${t}Repository {
2476
- constructor(@Inject(DRIZZLE_DB) private db: any) {}
2477
-
2478
- async findById(id: string): Promise<${t}ResponseDTO | null> {
2479
- // TODO: Implement with Drizzle
2480
- // const row = this.db.select().from(${n}s).where(eq(${n}s.id, id)).get()
2481
- // return row ?? null
2482
- throw new Error('Drizzle ${t} repository not yet implemented — update schema imports and queries')
2483
- }
2484
-
2485
- async findAll(): Promise<${t}ResponseDTO[]> {
2486
- // TODO: Implement with Drizzle
2487
- // return this.db.select().from(${n}s).all()
2488
- throw new Error('Drizzle ${t} repository not yet implemented')
2489
- }
2490
-
2491
- async findPaginated(parsed: ParsedQuery): Promise<{ data: ${t}ResponseDTO[]; total: number }> {
2492
- // TODO: Use buildFromColumns() with your query config for type-safe filtering
2493
- // const query = queryAdapter.buildFromColumns(parsed, ${t.toUpperCase()}_QUERY_CONFIG)
2494
- //
2495
- // const data = this.db
2496
- // .select().from(${n}s).$dynamic()
2497
- // .where(query.where).orderBy(...query.orderBy)
2498
- // .limit(query.limit).offset(query.offset).all()
2499
- //
2500
- // const totalResult = this.db
2501
- // .select({ count: count() }).from(${n}s)
2502
- // .$dynamic().where(query.where).get()
2503
- //
2504
- // return { data, total: totalResult?.count ?? 0 }
2505
- throw new Error('Drizzle ${t} repository not yet implemented')
2506
- }
2507
-
2508
- async create(dto: Create${t}DTO): Promise<${t}ResponseDTO> {
2509
- // TODO: Implement with Drizzle
2510
- // return this.db.insert(${n}s).values(dto).returning().get()
2511
- throw new Error('Drizzle ${t} repository not yet implemented')
2512
- }
2513
-
2514
- async update(id: string, dto: Update${t}DTO): Promise<${t}ResponseDTO> {
2515
- // TODO: Implement with Drizzle
2516
- // const row = this.db.update(${n}s).set(dto).where(eq(${n}s.id, id)).returning().get()
2517
- // if (!row) throw HttpException.notFound('${t} not found')
2518
- // return row
2519
- throw new Error('Drizzle ${t} repository not yet implemented')
2520
- }
2521
-
2522
- async delete(id: string): Promise<void> {
2523
- // TODO: Implement with Drizzle
2524
- // this.db.delete(${n}s).where(eq(${n}s.id, id)).run()
2525
- throw new Error('Drizzle ${t} repository not yet implemented')
2526
- }
2527
- }
2528
- `}function Kn(e){let{pascal:t,kebab:n}=e;return`import type { DrizzleQueryParamsConfig } from '@forinda/kickjs-drizzle'
2529
- // TODO: Import your schema table and reference actual columns for type safety
2530
- // import { ${n}s } from '@/db/schema'
2531
-
2532
- export const ${t.toUpperCase()}_QUERY_CONFIG: DrizzleQueryParamsConfig = {
2533
- columns: {
2534
- // Replace with actual Drizzle Column references for type-safe filtering:
2535
- // name: ${n}s.name,
2536
- // status: ${n}s.status,
2537
- },
2538
- sortable: {
2539
- // name: ${n}s.name,
2540
- // createdAt: ${n}s.createdAt,
2541
- },
2542
- searchColumns: [
2543
- // ${n}s.name,
2544
- ],
2545
- }
2546
- `}function qn(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`/**
2547
- * Prisma ${t} Repository
2548
- *
2549
- * Implements the repository interface using Prisma Client.
2550
- * Requires a PrismaClient instance injected via the DI container.
2551
- *
2552
- * Ensure your Prisma schema has a '${t}' model defined.
2553
- *
2554
- * For full Prisma field-level type safety, replace PrismaModelDelegate with your PrismaClient:
2555
- * @Inject(PRISMA_CLIENT) private prisma!: PrismaClient
2556
- *
2557
- * @Repository() registers this class in the DI container as a singleton.
2558
- */
2559
- import { Repository, HttpException, Inject } from '@forinda/kickjs'
2560
- import { PRISMA_CLIENT, type PrismaModelDelegate } from '@forinda/kickjs-prisma'
2561
- import type { ParsedQuery } from '@forinda/kickjs'
2562
- import type { I${t}Repository } from '${r}/${n}.repository'
2563
- import type { ${t}ResponseDTO } from '${i}/${n}-response.dto'
2564
- import type { Create${t}DTO } from '${i}/create-${n}.dto'
2565
- import type { Update${t}DTO } from '${i}/update-${n}.dto'
2566
-
2567
- @Repository()
2568
- export class Prisma${t}Repository implements I${t}Repository {
2569
- @Inject(PRISMA_CLIENT) private prisma!: { ${a}: PrismaModelDelegate }
2570
-
2571
- async findById(id: string): Promise<${t}ResponseDTO | null> {
2572
- return this.prisma.${a}.findUnique({ where: { id } }) as Promise<${t}ResponseDTO | null>
2573
- }
2574
-
2575
- async findAll(): Promise<${t}ResponseDTO[]> {
2576
- return this.prisma.${a}.findMany() as Promise<${t}ResponseDTO[]>
2577
- }
2578
-
2579
- async findPaginated(parsed: ParsedQuery): Promise<{ data: ${t}ResponseDTO[]; total: number }> {
2580
- const [data, total] = await Promise.all([
2581
- this.prisma.${a}.findMany({
2582
- skip: parsed.pagination.offset,
2583
- take: parsed.pagination.limit,
2584
- }) as Promise<${t}ResponseDTO[]>,
2585
- this.prisma.${a}.count(),
2586
- ])
2587
- return { data, total }
2588
- }
2589
-
2590
- async create(dto: Create${t}DTO): Promise<${t}ResponseDTO> {
2591
- return this.prisma.${a}.create({ data: dto as Record<string, unknown> }) as Promise<${t}ResponseDTO>
2592
- }
2593
-
2594
- async update(id: string, dto: Update${t}DTO): Promise<${t}ResponseDTO> {
2595
- const existing = await this.prisma.${a}.findUnique({ where: { id } })
2596
- if (!existing) throw HttpException.notFound('${t} not found')
2597
- return this.prisma.${a}.update({ where: { id }, data: dto as Record<string, unknown> }) as Promise<${t}ResponseDTO>
2598
- }
2599
-
2600
- async delete(id: string): Promise<void> {
2601
- await this.prisma.${a}.deleteMany({ where: { id } })
2602
- }
2603
- }
2604
- `}async function Jn(e){let{pascal:t,kebab:n,plural:r,style:i,write:a}=e;await a(`${n}.module.ts`,Cn({pascal:t,kebab:n,plural:r,style:i})),await a(`${n}.controller.ts`,`import { Controller, Get, type Ctx } from '@forinda/kickjs'
2605
-
2606
- // \`Ctx<KickRoutes.${t}Controller['<method>']>\` is generated by
2607
- // \`kick typegen\` (auto-run on \`kick dev\`).
1721
+ // \`Ctx<KickRoutes.${t}Controller['<method>']>\` is generated by
1722
+ // \`kick typegen\` (auto-run on \`kick dev\`).
2608
1723
 
2609
1724
  @Controller()
2610
1725
  export class ${t}Controller {
@@ -2613,7 +1728,7 @@ export class ${t}Controller {
2613
1728
  ctx.json({ message: '${t} list' })
2614
1729
  }
2615
1730
  }
2616
- `)}async function Yn(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`,Sn({pascal:t,kebab:n,plural:r,repo:a,style:l})),await u(`${n}.constants.ts`,zn({pascal:t,kebab:n})),await u(`${n}.controller.ts`,Tn({pascal:t,kebab:n,plural:r,pluralPascal:i})),await u(`${n}.service.ts`,Rn({pascal:t,kebab:n})),await u(`dtos/create-${n}.dto.ts`,Dn({pascal:t,kebab:n})),await u(`dtos/update-${n}.dto.ts`,On({pascal:t,kebab:n})),await u(`dtos/${n}-response.dto.ts`,kn({pascal:t,kebab:n})),await u(`${n}.repository.ts`,jn({pascal:t,kebab:n,dtoPrefix:`./dtos`,tokenScope:c}));let d={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},f={inmemory:()=>V({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),drizzle:()=>Gn({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),prisma:()=>qn({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`,prismaClientPath:s})},p=d[a]??`${R(a)}-${n}`,m=f[a]??(()=>Mn({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`,V({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`})),await u(`__tests__/${n}.controller.test.ts`,In({pascal:t,kebab:n,plural:r})),await u(`__tests__/${n}.repository.test.ts`,Ln({pascal:t,kebab:n,plural:r,repoPrefix:`../${d.inmemory??`in-memory-${n}`}.repository`})))}async function Xn(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`,Bn({pascal:t,kebab:n,plural:r,repo:a,style:l})),await u(`${n}.constants.ts`,zn({pascal:t,kebab:n})),await u(`${n}.controller.ts`,Vn({pascal:t,kebab:n,plural:r,pluralPascal:i})),await u(`dtos/create-${n}.dto.ts`,Dn({pascal:t,kebab:n})),await u(`dtos/update-${n}.dto.ts`,On({pascal:t,kebab:n})),await u(`dtos/${n}-response.dto.ts`,kn({pascal:t,kebab:n}));let d=Hn({pascal:t,kebab:n});for(let e of d)await u(`commands/${e.file}`,e.content);let f=Un({pascal:t,kebab:n,plural:r,pluralPascal:i});for(let e of f)await u(`queries/${e.file}`,e.content);let p=Wn({pascal:t,kebab:n});for(let e of p)await u(`events/${e.file}`,e.content);await u(`${n}.repository.ts`,jn({pascal:t,kebab:n,dtoPrefix:`./dtos`,tokenScope:c}));let m={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},h={inmemory:()=>V({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),drizzle:()=>Gn({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),prisma:()=>qn({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`,prismaClientPath:s})},g=m[a]??`${R(a)}-${n}`,_=h[a]??(()=>Mn({pascal:t,kebab:n,repoType:a,repoPrefix:`.`,dtoPrefix:`./dtos`}));await u(`${g}.repository.ts`,_()),o||(a!==`inmemory`&&await u(`in-memory-${n}.repository.ts`,V({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`})),await u(`__tests__/${n}.controller.test.ts`,In({pascal:t,kebab:n,plural:r})),await u(`__tests__/${n}.repository.test.ts`,Ln({pascal:t,kebab:n,plural:r,repoPrefix:`../${m.inmemory??`in-memory-${n}`}.repository`})))}async function Zn(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`,xn({pascal:t,kebab:n,plural:r,repo:a,style:u})),await d(`constants.ts`,a===`drizzle`?Kn({pascal:t,kebab:n}):En({pascal:t,kebab:n})),await d(`presentation/${n}.controller.ts`,wn({pascal:t,kebab:n,plural:r,pluralPascal:i})),await d(`application/dtos/create-${n}.dto.ts`,Dn({pascal:t,kebab:n})),await d(`application/dtos/update-${n}.dto.ts`,On({pascal:t,kebab:n})),await d(`application/dtos/${n}-response.dto.ts`,kn({pascal:t,kebab:n}));let f=An({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`,jn({pascal:t,kebab:n,tokenScope:l})),await d(`domain/services/${n}-domain.service.ts`,Nn({pascal:t,kebab:n}));let p={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},m={inmemory:()=>V({pascal:t,kebab:n}),drizzle:()=>Gn({pascal:t,kebab:n}),prisma:()=>qn({pascal:t,kebab:n,prismaClientPath:c})},h=p[a]??`${R(a)}-${n}`,g=m[a]??(()=>Mn({pascal:t,kebab:n,repoType:a}));await d(`infrastructure/repositories/${h}.repository.ts`,g()),o||(await d(`domain/entities/${n}.entity.ts`,Pn({pascal:t,kebab:n})),await d(`domain/value-objects/${n}-id.vo.ts`,Fn({pascal:t,kebab:n}))),s||(a!==`inmemory`&&await d(`infrastructure/repositories/in-memory-${n}.repository.ts`,V({pascal:t,kebab:n})),await d(`__tests__/${n}.controller.test.ts`,In({pascal:t,kebab:n,plural:r})),await d(`__tests__/${n}.repository.test.ts`,Ln({pascal:t,kebab:n,plural:r})))}function Qn(e){return e?typeof e==`string`?e:e.name:`inmemory`}async function $n(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=R(t),d=I(t),f=c?z(u):u,p=c?Zt(d):d,m=h(n,f),g=[],_=o??!1,v={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=h(m,e);if(s){g.push(n);return}if(!_&&await Qe(n)&&!await P({message:`File exists: ${E.dim(e)}. Overwrite?`,initialValue:!1})){F.warn(`Skipped: ${e}`);return}await M(n,t),g.push(n)},files:g};switch(l){case`minimal`:await Jn(v);break;case`rest`:await Yn(v);break;case`cqrs`:await Xn(v);break;default:await Zn(v);break}return s||await er(n,d,f,u,v.style),g}async function er(e,t,n,r,i=`define`){let a=h(e,`index.ts`),o=await Qe(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'
1731
+ `)}async function wn(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noTests:o,tokenScope:s,style:c,write:l}=e;await l(`${n}.module.ts`,un({pascal:t,kebab:n,plural:r,repo:a,style:c})),await l(`${n}.constants.ts`,Sn({pascal:t,kebab:n})),await l(`${n}.controller.ts`,fn({pascal:t,kebab:n,plural:r,pluralPascal:i})),await l(`${n}.service.ts`,xn({pascal:t,kebab:n})),await l(`dtos/create-${n}.dto.ts`,pn({pascal:t,kebab:n})),await l(`dtos/update-${n}.dto.ts`,mn({pascal:t,kebab:n})),await l(`dtos/${n}-response.dto.ts`,hn({pascal:t,kebab:n})),await l(`${n}.repository.ts`,gn({pascal:t,kebab:n,dtoPrefix:`./dtos`,tokenScope:s}));let u=a===`inmemory`,d=u?`in-memory-${n}`:`${B(a)}-${n}`,f=u?_n({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}):vn({pascal:t,kebab:n,repoType:a,repoPrefix:`.`,dtoPrefix:`./dtos`});await l(`${d}.repository.ts`,f),o||(a!==`inmemory`&&await l(`in-memory-${n}.repository.ts`,_n({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`})),await l(`__tests__/${n}.controller.test.ts`,yn({pascal:t,kebab:n,plural:r})),await l(`__tests__/${n}.repository.test.ts`,bn({pascal:t,kebab:n,plural:r,repoPrefix:`../in-memory-${n}.repository`})))}function Tn(e){return e?typeof e==`string`?e:e.name:`inmemory`}async function En(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??`rest`;e.minimal&&(l=`minimal`);let u=B(t),d=R(t),f=c?V(u):u,p=c?Ht(d):d,m=h(n,f),g=[],_=o??!1,v={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=h(m,e);if(s){g.push(n);return}if(!_&&await Ue(n)&&!await I({message:`File exists: ${k.dim(e)}. Overwrite?`,initialValue:!1})){L.warn(`Skipped: ${e}`);return}await P(n,t),g.push(n)},files:g};switch(l){case`minimal`:await Cn(v);break;default:await wn(v);break}return s||await Dn(n,d,f,u,v.style),g}async function Dn(e,t,n,r,i=`define`){let a=h(e,`index.ts`),o=await Ue(a),s=`./${n}/${r}.module`,c=i===`class`?`${t}Module`:`${t}Module()`;if(!o){await P(a,i===`class`?`import type { AppModuleEntry } from '@forinda/kickjs'
2617
1732
  import { ${t}Module } from '${s}'
2618
1733
 
2619
1734
  export const modules: AppModuleEntry[] = [${c}]
@@ -2621,11 +1736,11 @@ export const modules: AppModuleEntry[] = [${c}]
2621
1736
  import { ${t}Module } from '${s}'
2622
1737
 
2623
1738
  export const modules = defineModules().mount(${c})
2624
- `);return}let l=await C(a,`utf-8`),u=`import { ${t}Module } from '${s}'`,d=B(s);if(!RegExp(`^import\\s*\\{[^}]*\\b${B(t)}Module\\b[^}]*\\}\\s*from\\s*['"]${d}['"]`,`m`).test(l)){let e=l.lastIndexOf(`import `);if(e!==-1){let t=l.indexOf(`
1739
+ `);return}let l=await T(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(`
2625
1740
  `,e);l=l.slice(0,t+1)+u+`
2626
1741
  `+l.slice(t+1)}else l=u+`
2627
- `+l}let f=nr(l);if(f){let e=l.slice(f.rhsStart,f.rhsEnd+1);RegExp(`\\b${B(t)}Module\\b`).test(e)||(l=tr(l,c))}else l=tr(l,c);await w(a,l,`utf-8`)}function tr(e,t){let n=nr(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 nr(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=ar(e,n);return t===-1?null:{shape:`array`,rhsStart:n,rhsEnd:t}}if(e.slice(n,n+13)===`defineModules`){let t=rr(e,n);return t===-1?null:{shape:`chain`,rhsStart:n,rhsEnd:t-1,chainEnd:t}}return null}function rr(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=or(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=or(e,t);if(n===-1)break;i=n+1}return i}function ir(e,t){let n=e.slice(t,t+2);if(n===`//`){for(t+=2;t<e.length&&e[t]!==`
2628
- `;)t++;return t}if(n===`/*`){for(t+=2;t+1<e.length&&!(e[t]===`*`&&e[t+1]===`/`);)t++;return t+2}return t}function ar(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=ir(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 or(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=ir(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 sr(e){let{name:t,outDir:n}=e,r=R(t),i=I(t),a=[],o=h(n,`${r}.adapter.ts`);return await M(o,`import {
1742
+ `+l}let f=kn(l);if(f){let e=l.slice(f.rhsStart,f.rhsEnd+1);RegExp(`\\b${H(t)}Module\\b`).test(e)||(l=On(l,c))}else l=On(l,c);await E(a,l,`utf-8`)}function On(e,t){let n=kn(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 kn(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=Mn(e,n);return t===-1?null:{shape:`array`,rhsStart:n,rhsEnd:t}}if(e.slice(n,n+13)===`defineModules`){let t=An(e,n);return t===-1?null:{shape:`chain`,rhsStart:n,rhsEnd:t-1,chainEnd:t}}return null}function An(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=Nn(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=Nn(e,t);if(n===-1)break;i=n+1}return i}function jn(e,t){let n=e.slice(t,t+2);if(n===`//`){for(t+=2;t<e.length&&e[t]!==`
1743
+ `;)t++;return t}if(n===`/*`){for(t+=2;t+1<e.length&&!(e[t]===`*`&&e[t+1]===`/`);)t++;return t+2}return t}function Mn(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=jn(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 Nn(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=jn(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 Pn(e){let{name:t,outDir:n}=e,r=B(t),i=R(t),a=[],o=h(n,`${r}.adapter.ts`);return await P(o,`import {
2629
1744
  defineAdapter,
2630
1745
  type AdapterContext,
2631
1746
  type AdapterMiddleware,
@@ -2794,7 +1909,7 @@ export const ${i}Adapter = defineAdapter<${i}AdapterConfig>({
2794
1909
  }
2795
1910
  },
2796
1911
  })
2797
- `),a.push(o),a}async function cr(e){let{name:t,outDir:n}=e,r=R(t),i=I(t),a=[],o=h(n,`${r}.plugin.ts`);return await M(o,`import {
1912
+ `),a.push(o),a}async function Fn(e){let{name:t,outDir:n}=e,r=B(t),i=R(t),a=[],o=h(n,`${r}.plugin.ts`);return await P(o,`import {
2798
1913
  definePlugin,
2799
1914
  type AppAdapter,
2800
1915
  type AppModuleEntry,
@@ -2938,9 +2053,9 @@ export const ${i}Plugin = definePlugin<${i}PluginConfig>({
2938
2053
  },
2939
2054
  }),
2940
2055
  })
2941
- `),a.push(o),a}const lr={controller:`presentation`,service:`domain/services`,dto:`application/dtos`,guard:`presentation/guards`,middleware:`middleware`,contributor:`presentation/contributors`},ur={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`,contributor:`contributors`},dr={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`,contributor:`contributors`,command:`commands`,query:`queries`,event:`events`};function H(e){let{type:t,outDir:n,moduleName:r,modulesDir:i=`src/modules`,defaultDir:a,pattern:o=`ddd`,shouldPluralize:s=!0}=e;if(n)return v(n);if(r){let e=o===`ddd`?lr:o===`cqrs`?dr:ur,n=R(r),a=s?z(n):n,c=e[t]??``,l=h(i,a);return v(c?h(l,c):l)}return v(a)}async function fr(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=H({type:`middleware`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/middleware`,pattern:i,shouldPluralize:e.pluralize??!0}),o=R(t),s=L(t),c=[],l=h(a,`${o}.middleware.ts`);return await M(l,`import type { Request, Response, NextFunction } from 'express'
2056
+ `),a.push(o),a}const In={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`,contributor:`contributors`};function U(e){let{type:t,outDir:n,moduleName:r,modulesDir:i=`src/modules`,defaultDir:a,shouldPluralize:o=!0}=e;if(n)return v(n);if(r){let e=In,n=B(r),a=o?V(n):n,s=e[t]??``,c=h(i,a);return v(s?h(c,s):c)}return v(a)}async function Ln(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=h(a,`${o}.middleware.ts`);return await P(l,`import type { Request, Response, NextFunction } from 'express'
2942
2057
 
2943
- export interface ${I(t)}Options {
2058
+ export interface ${R(t)}Options {
2944
2059
  // Add configuration options here. The factory below closes over the
2945
2060
  // resolved options object; pass them at the call site —
2946
2061
  // \`${s}({ foo: 'bar' })\` — and the closure preserves them across
@@ -2948,7 +2063,7 @@ export interface ${I(t)}Options {
2948
2063
  }
2949
2064
 
2950
2065
  /**
2951
- * ${I(t)} middleware.
2066
+ * ${R(t)} middleware.
2952
2067
  *
2953
2068
  * Usage in bootstrap (fires on every request):
2954
2069
  * middleware: [${s}()]
@@ -2980,7 +2095,7 @@ export interface ${I(t)}Options {
2980
2095
  * Usage with @Middleware decorator:
2981
2096
  * @Middleware(${s}())
2982
2097
  */
2983
- export function ${s}(options: ${I(t)}Options = {}) {
2098
+ export function ${s}(options: ${R(t)}Options = {}) {
2984
2099
  return (req: Request, res: Response, next: NextFunction) => {
2985
2100
  // Implement your middleware logic here. \`options\` is captured by
2986
2101
  // closure — log or read it anywhere in this handler body.
@@ -2988,7 +2103,7 @@ export function ${s}(options: ${I(t)}Options = {}) {
2988
2103
  next()
2989
2104
  }
2990
2105
  }
2991
- `),c.push(l),c}async function pr(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=H({type:`guard`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/guards`,pattern:i,shouldPluralize:e.pluralize??!0}),o=R(t),s=L(t),c=I(t),l=[],u=h(a,`${o}.guard.ts`);return await M(u,`import { Container, HttpException } from '@forinda/kickjs'
2106
+ `),c.push(l),c}async function Rn(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=h(a,`${o}.guard.ts`);return await P(u,`import { Container, HttpException } from '@forinda/kickjs'
2992
2107
  import type { RequestContext } from '@forinda/kickjs'
2993
2108
 
2994
2109
  /**
@@ -3024,8 +2139,8 @@ export async function ${s}Guard(ctx: RequestContext, next: () => void): Promise<
3024
2139
  ctx.res.status(401).json({ message: 'Invalid or expired token' })
3025
2140
  }
3026
2141
  }
3027
- `),l.push(u),l}function mr(e){return e?e.split(`,`).map(e=>e.trim()).filter(Boolean).map(e=>{let[t,n]=e.split(`:`).map(e=>e.trim());return{name:t,type:n||`string`}}).filter(e=>e.name.length>0):[]}function hr(e){switch(e){case`string`:return`''`;case`number`:return`0`;case`boolean`:return`false`;default:return null}}async function gr(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=e.type??`http`,o=R(t),s=I(t),c=e.key??L(t),l=Array.isArray(e.params)?e.params:mr(e.params),u=H({type:`contributor`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/contributors`,pattern:i,shouldPluralize:e.pluralize??!0}),d=a===`http`?`defineHttpContextDecorator`:`defineContextDecorator`,f=a===`http`?`RequestContext`:`ExecutionContext`,p=l.length>0?`\nexport type ${s}Params = {\n${l.map(e=>` ${e.name}: ${e.type}`).join(`
3028
- `)}\n}\n`:``,m=l.length>0?`${d}.withParams<${s}Params>()({`:`${d}({`,g=l.map(e=>({name:e.name,def:hr(e.type)})).filter(e=>e.def!==null).map(e=>` ${e.name}: ${e.def},`),_=l.length>0?` paramDefaults: {\n${g.join(`
2142
+ `),l.push(u),l}function zn(e){return e?e.split(`,`).map(e=>e.trim()).filter(Boolean).map(e=>{let[t,n]=e.split(`:`).map(e=>e.trim());return{name:t,type:n||`string`}}).filter(e=>e.name.length>0):[]}function Bn(e){switch(e){case`string`:return`''`;case`number`:return`0`;case`boolean`:return`false`;default:return null}}async function Vn(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=e.type??`http`,o=B(t),s=R(t),c=e.key??z(t),l=Array.isArray(e.params)?e.params:zn(e.params),u=U({type:`contributor`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/contributors`,pattern:i,shouldPluralize:e.pluralize??!0}),d=a===`http`?`defineHttpContextDecorator`:`defineContextDecorator`,f=a===`http`?`RequestContext`:`ExecutionContext`,p=l.length>0?`\nexport type ${s}Params = {\n${l.map(e=>` ${e.name}: ${e.type}`).join(`
2143
+ `)}\n}\n`:``,m=l.length>0?`${d}.withParams<${s}Params>()({`:`${d}({`,g=l.map(e=>({name:e.name,def:Bn(e.type)})).filter(e=>e.def!==null).map(e=>` ${e.name}: ${e.def},`),_=l.length>0?` paramDefaults: {\n${g.join(`
3029
2144
  `)}\n },\n`:``,v=l.length>0?`(ctx, _deps, params)`:`(ctx)`,y=l.length>0?` // \`params\` is typed as ${s}Params (call-site overrides merged onto paramDefaults).`:` // \`ctx\` is a ${f} — read ctx.req / ctx.headers / ctx.params (http) or ctx.get (bare).`,b=`import { ${d} } from '@forinda/kickjs'
3030
2145
  import type { ${f} } from '@forinda/kickjs'
3031
2146
 
@@ -3064,7 +2179,7 @@ ${y}
3064
2179
  throw new Error("${s} contributor: resolve() not implemented")
3065
2180
  },
3066
2181
  })
3067
- `,x=h(u,`${o}.contributor.ts`);return await M(x,b),[x]}async function _r(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=H({type:`service`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/services`,pattern:i,shouldPluralize:e.pluralize??!0}),o=R(t),s=I(t),c=[],l=h(a,`${o}.service.ts`);return await M(l,`import { Service } from '@forinda/kickjs'
2182
+ `,x=h(u,`${o}.contributor.ts`);return await P(x,b),[x]}async function Hn(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=h(a,`${o}.service.ts`);return await P(l,`import { Service } from '@forinda/kickjs'
3068
2183
 
3069
2184
  @Service()
3070
2185
  export class ${s}Service {
@@ -3073,7 +2188,7 @@ export class ${s}Service {
3073
2188
  // @Inject(MY_REPO) private readonly repo: IMyRepository,
3074
2189
  // ) {}
3075
2190
  }
3076
- `),c.push(l),c}async function vr(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=H({type:`controller`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/controllers`,pattern:i,shouldPluralize:e.pluralize??!0}),o=R(t),s=I(t),c=[],l=h(a,`${o}.controller.ts`);return await M(l,`import { Controller, Get, Post, type Ctx } from '@forinda/kickjs'
2191
+ `),c.push(l),c}async function Un(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=h(a,`${o}.controller.ts`);return await P(l,`import { Controller, Get, Post, type Ctx } from '@forinda/kickjs'
3077
2192
 
3078
2193
  // \`Ctx<KickRoutes.${s}Controller['<method>']>\` is generated by
3079
2194
  // \`kick typegen\` (auto-run on \`kick dev\`). After the first run, your IDE
@@ -3094,7 +2209,7 @@ export class ${s}Controller {
3094
2209
  ctx.created({ message: '${s} created', data: ctx.body })
3095
2210
  }
3096
2211
  }
3097
- `),c.push(l),c}async function yr(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=H({type:`dto`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/dtos`,pattern:i,shouldPluralize:e.pluralize??!0}),o=R(t),s=I(t),c=L(t),l=[],u=h(a,`${o}.dto.ts`);return await M(u,`import { z } from 'zod'
2212
+ `),c.push(l),c}async function Wn(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=h(a,`${o}.dto.ts`);return await P(u,`import { z } from 'zod'
3098
2213
 
3099
2214
  export const ${c}Schema = z.object({
3100
2215
  // Define your schema fields here
@@ -3102,8 +2217,8 @@ export const ${c}Schema = z.object({
3102
2217
  })
3103
2218
 
3104
2219
  export type ${s}DTO = z.infer<typeof ${c}Schema>
3105
- `),l.push(u),l}async function br(e){let t=h(e.outDir,`kick.config.ts`),n=e.modulesDir??`src/modules`,i=e.defaultRepo??`inmemory`;return r(t)&&!e.force&&!await P({message:`kick.config.ts already exists. Overwrite?`,initialValue:!1})?(console.log(`
3106
- Skipped — existing kick.config.ts preserved.`),[]):(await M(t,`import { defineConfig } from '@forinda/kickjs-cli'
2220
+ `),l.push(u),l}async function Gn(e){let t=h(e.outDir,`kick.config.ts`),n=e.modulesDir??`src/modules`,i=e.defaultRepo??`inmemory`;return r(t)&&!e.force&&!await I({message:`kick.config.ts already exists. Overwrite?`,initialValue:!1})?(console.log(`
2221
+ Skipped — existing kick.config.ts preserved.`),[]):(await P(t,`import { defineConfig } from '@forinda/kickjs-cli'
3107
2222
 
3108
2223
  export default defineConfig({
3109
2224
  modules: {
@@ -3140,18 +2255,18 @@ export default defineConfig({
3140
2255
  },
3141
2256
  ],
3142
2257
  })
3143
- `),[t])}var xr=D({generateAgentDocs:()=>Dr});const Sr=`.agents`,Cr=new Set([`rest`,`ddd`,`cqrs`,`minimal`]);function wr(e,t){if(t)return t;try{let t=JSON.parse(a(h(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(a(h(e,`package.json`),`utf-8`));if(t.packageManager)return t.packageManager.split(`@`)[0]}catch{}return`pnpm`}async function Er(e,t){if(t)return t;try{let t=(await k(e))?.pattern;if(t&&Cr.has(t))return t}catch{}return`ddd`}async function Dr(e){let t=e.only??`all`,n=wr(e.outDir,e.name),i=Tr(e.outDir,e.pm),a=await Er(e.outDir,e.template),o=t===`agents`||t===`both`||t===`all`,s=t===`claude`||t===`both`||t===`all`,c=t===`skills`||t===`all`,l=t===`gemini`||t===`all`,u=t===`copilot`||t===`all`,d=[];if(o&&d.push({file:h(e.outDir,Sr,`AGENTS.md`),render:()=>xt(n,a,i)}),s&&d.push({file:h(e.outDir,`CLAUDE.md`),render:()=>bt(n,a,i)}),c)for(let t of St(n,a,i))d.push({file:h(e.outDir,Sr,`skills`,t.slug,`SKILL.md`),render:()=>t.content});l&&d.push({file:h(e.outDir,Sr,`GEMINI.md`),render:()=>Ct(n,a,i)}),u&&d.push({file:h(e.outDir,Sr,`COPILOT.md`),render:()=>wt(n,a,i)});let f=[];for(let{file:t,render:n}of d){if(r(t)&&!e.force&&!await P({message:`${t.replace(e.outDir+`/`,``)} already exists. Overwrite?`,initialValue:!1})){console.log(` Skipped — existing ${t.replace(e.outDir+`/`,``)} preserved.`);continue}await M(t,n()),f.push(t)}return f}function Or(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 U(e,t){let n=t.exec(e);if(!n)return null;let r=n.index+n[0].length-1,i=Or(e,r);return i===-1?null:e.slice(r+1,i)}function W(e,t,n){let r=` `.repeat(n);return e.split(`
2258
+ `),[t])}var Kn=A({generateAgentDocs:()=>Qn});const qn=`.agents`,Jn=new Set([`rest`,`minimal`]);function Yn(e,t){if(t)return t;try{let t=JSON.parse(a(h(e,`package.json`),`utf-8`));if(t.name)return t.name.replace(/^@[^/]+\//,``)}catch{}return e.split(`/`).findLast(Boolean)??`app`}function Xn(e,t){if(t)return t;try{let t=JSON.parse(a(h(e,`package.json`),`utf-8`));if(t.packageManager)return t.packageManager.split(`@`)[0]}catch{}return`pnpm`}async function Zn(e,t){if(t)return t;try{let t=(await M(e))?.pattern;if(t&&Jn.has(t))return t}catch{}return`rest`}async function Qn(e){let t=e.only??`all`,n=Yn(e.outDir,e.name),i=Xn(e.outDir,e.pm),a=await Zn(e.outDir,e.template),o=t===`agents`||t===`both`||t===`all`,s=t===`claude`||t===`both`||t===`all`,c=t===`skills`||t===`all`,l=t===`gemini`||t===`all`,u=t===`copilot`||t===`all`,d=[];if(o&&d.push({file:h(e.outDir,qn,`AGENTS.md`),render:()=>ft(n,a,i)}),s&&d.push({file:h(e.outDir,`CLAUDE.md`),render:()=>dt(n,a,i)}),c)for(let t of pt(n,a,i))d.push({file:h(e.outDir,qn,`skills`,t.slug,`SKILL.md`),render:()=>t.content});l&&d.push({file:h(e.outDir,qn,`GEMINI.md`),render:()=>mt(n,a,i)}),u&&d.push({file:h(e.outDir,qn,`COPILOT.md`),render:()=>ht(n,a,i)});let f=[];for(let{file:t,render:n}of d){if(r(t)&&!e.force&&!await I({message:`${t.replace(e.outDir+`/`,``)} already exists. Overwrite?`,initialValue:!1})){console.log(` Skipped — existing ${t.replace(e.outDir+`/`,``)} preserved.`);continue}await P(t,n()),f.push(t)}return f}function $n(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=$n(e,r);return i===-1?null:e.slice(r+1,i)}function G(e,t,n){let r=` `.repeat(n);return e.split(`
3144
2259
  `).map(e=>{if(e.trim()===``)return e;let n=RegExp(`^ {0,${t}}`);return r+e.replace(n,``)}).join(`
3145
- `)}function kr(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 Ar(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 jr(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=Or(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=U(o,/register\s*\(([^)]*)\)\s*:\s*void\s*\{/),u=U(o,/contributors\s*\(\s*\)\s*:\s*ContributorRegistrations\s*\{/),d=U(o,/routes\s*\(\s*\)\s*:\s*[A-Za-z|[\]\s]+\{/);if(!d)return{migrated:null,reason:`routes() method missing or signature unrecognized`};let f=kr(s),p=``;return l&&(p+=` register(container) {${W(l,4,6)} },\n\n`),u&&(p+=` contributors() {${W(u,4,6)} },\n\n`),p+=` routes() {${W(d,4,6)} },`,{migrated:`${f}${`export const ${r} = defineModule({
2260
+ `)}function er(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 tr(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 nr(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=$n(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=er(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({
3146
2261
  name: '${r}',
3147
2262
  build: () => ({
3148
2263
  ${p}
3149
2264
  }),
3150
- })`}${c}`}}function Mr(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=Or(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]===`
3151
- `||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=Or(s,f);if(p===-1)return{migrated:null,reason:`unbalanced build() braces`};let m=s.slice(f+1,p),h=U(m,/register\s*\(([^)]*)\)\s*\{/),g=U(m,/contributors\s*\(\s*\)\s*\{/),_=U(m,/routes\s*\(\s*\)\s*\{/);if(!_)return{migrated:null,reason:`routes() method missing inside build()`};let v=Ar(c,{container:h!==null,appModule:!0,moduleRoutes:!0,contributorRegistrations:g!==null}),y=``;return h!==null&&(y+=` register(container: Container): void {${W(h,6,4)} }\n\n`),g!==null&&(y+=` contributors(): ContributorRegistrations {${W(g,6,4)} }\n\n`),y+=` routes(): ModuleRoutes {${W(_,6,4)} }`,{migrated:`${v}${`export class ${r} implements AppModule {
2265
+ })`}${c}`}}function rr(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=$n(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]===`
2266
+ `||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=$n(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 v=tr(c,{container:h!==null,appModule:!0,moduleRoutes:!0,contributorRegistrations:g!==null}),y=``;return h!==null&&(y+=` register(container: Container): void {${G(h,6,4)} }\n\n`),g!==null&&(y+=` contributors(): ContributorRegistrations {${G(g,6,4)} }\n\n`),y+=` routes(): ModuleRoutes {${G(_,6,4)} }`,{migrated:`${v}${`export class ${r} implements AppModule {
3152
2267
  ${y}
3153
2268
  }
3154
- `}${u}`}}function Nr(e,t){return t===`class`?Mr(e):jr(e)}function Pr(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 Fr(e){let t=[];return await n(v(e),0),t;async function n(e,r){let i;try{i=await se(e)}catch{return}for(let a of i){if(a===`node_modules`||a===`dist`||a===`.kickjs`)continue;let i=h(e,a),o;try{o=await le(i)}catch{continue}o.isDirectory()?await n(i,r+1):(a.endsWith(`.module.ts`)||a===`index.ts`&&r===1)&&t.push(i)}}}async function Ir(e,t){let n=0;return await r(e,t),n;async function r(e,t){let i;try{i=await se(e)}catch{return}await oe(t,{recursive:!0});for(let a of i){if(a===`node_modules`||a===`dist`||a===`.kickjs`)continue;let i=h(e,a),o=h(t,a),s;try{s=await le(i)}catch{continue}s.isDirectory()?await r(i,o):(await ae(i,o),n++)}}}function Lr(e){return h(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 Fr(e),s=await C(h(e,`index.ts`),`utf-8`).then(()=>!0,()=>!1),c=null;a&&(o.length>0||s)&&(c=Lr(r),await Ir(e,c));let l=[];for(let e of o){let t=Nr(await C(e,`utf-8`),i);if(t.migrated==null){l.push({path:e,status:`skipped`,reason:t.reason});continue}n||await w(e,t.migrated,`utf-8`),l.push({path:e,status:`migrated`})}let u=h(e,`index.ts`),d=null;try{d=await C(u,`utf-8`)}catch{return{target:i,files:l,indexStatus:`not-found`,indexPath:u,backupDir:c}}let f=Pr(d,i);return f.migrated==null?{target:i,files:l,indexStatus:`skipped`,indexPath:u,indexReason:f.reason,backupDir:c}:(n||await w(u,f.migrated,`utf-8`),{target:i,files:l,indexStatus:`migrated`,indexPath:u,backupDir:c})}async function zr(e,t){let n=await Fr(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 C(e,`utf-8`);i.test(t)&&r.push(e)}return r}async function Br(e){let{name:t,outDir:n}=e,r=I(t),i=R(t),a=L(t),o=e.queue??`${i}-queue`,s=[];return await(async(e,t)=>{let r=h(n,e);await M(r,t),s.push(r)})(`${i}.job.ts`,`import { Inject } from '@forinda/kickjs'
2269
+ `}${u}`}}function ir(e,t){return t===`class`?rr(e):nr(e)}function ar(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 or(e){let t=[];return await n(v(e),0),t;async function n(e,r){let i;try{i=await ae(e)}catch{return}for(let a of i){if(a===`node_modules`||a===`dist`||a===`.kickjs`)continue;let i=h(e,a),o;try{o=await se(i)}catch{continue}o.isDirectory()?await n(i,r+1):(a.endsWith(`.module.ts`)||a===`index.ts`&&r===1)&&t.push(i)}}}async function sr(e,t){let n=0;return await r(e,t),n;async function r(e,t){let i;try{i=await ae(e)}catch{return}await w(t,{recursive:!0});for(let a of i){if(a===`node_modules`||a===`dist`||a===`.kickjs`)continue;let i=h(e,a),o=h(t,a),s;try{s=await se(i)}catch{continue}s.isDirectory()?await r(i,o):(await ie(i,o),n++)}}}function cr(e){return h(e,`.kickjs`,`codemod-backups`,`${new Date().toISOString().replaceAll(/[:.]/g,`-`)}-modules`)}async function lr(e,t){let{dryRun:n=!1,cwd:r=process.cwd(),target:i}=t,a=t.backup??!n,o=await or(e),s=await T(h(e,`index.ts`),`utf-8`).then(()=>!0,()=>!1),c=null;a&&(o.length>0||s)&&(c=cr(r),await sr(e,c));let l=[];for(let e of o){let t=ir(await T(e,`utf-8`),i);if(t.migrated==null){l.push({path:e,status:`skipped`,reason:t.reason});continue}n||await E(e,t.migrated,`utf-8`),l.push({path:e,status:`migrated`})}let u=h(e,`index.ts`),d=null;try{d=await T(u,`utf-8`)}catch{return{target:i,files:l,indexStatus:`not-found`,indexPath:u,backupDir:c}}let f=ar(d,i);return f.migrated==null?{target:i,files:l,indexStatus:`skipped`,indexPath:u,indexReason:f.reason,backupDir:c}:(n||await E(u,f.migrated,`utf-8`),{target:i,files:l,indexStatus:`migrated`,indexPath:u,backupDir:c})}async function ur(e,t){let n=await or(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 T(e,`utf-8`);i.test(t)&&r.push(e)}return r}async function dr(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=h(n,e);await P(r,t),s.push(r)})(`${i}.job.ts`,`import { Inject } from '@forinda/kickjs'
3155
2270
  import { Job, Process, QUEUE_MANAGER, type QueueService } from '@forinda/kickjs-queue'
3156
2271
 
3157
2272
  /**
@@ -3184,7 +2299,7 @@ export class ${r}Job {
3184
2299
  // Handle high-priority variant of this job
3185
2300
  }
3186
2301
  }
3187
- `),s}const Vr={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 Hr(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=Vr[a];if(!o){let e=[...Object.keys(Vr),`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 Ur(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=R(t),d=I(t);L(t);let f=l?z(u):u,p=l?Zt(d):d,m=h(r,f),g=[],_=async(e,t)=>{let n=h(m,e);await M(n,t),g.push(n)};await _(`${u}.module.ts`,Zr(d,u,f,c)),await _(`constants.ts`,qr(d,n)),await _(`presentation/${u}.controller.ts`,Qr(d,u,f,p)),await _(`application/dtos/create-${u}.dto.ts`,Wr(d,n)),await _(`application/dtos/update-${u}.dto.ts`,Gr(d,n)),await _(`application/dtos/${u}-response.dto.ts`,Kr(d,n));let v=ti(d,u,f,p);for(let e of v)await _(`application/use-cases/${e.file}`,e.content);return await _(`domain/repositories/${u}.repository.ts`,$r(d,u,s)),await _(`domain/services/${u}-domain.service.ts`,ei(d,u)),o===`inmemory`&&await _(`infrastructure/repositories/in-memory-${u}.repository.ts`,Jr(d,u,n)),i||(await _(`domain/entities/${u}.entity.ts`,Yr(d,u,n)),await _(`domain/value-objects/${u}-id.vo.ts`,Xr(d))),await er(r,d,f,u,c),g}function Wr(e,t){return`import { z } from 'zod'
2302
+ `),s}const fr={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 pr(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=fr[a];if(!o){let e=[...Object.keys(fr),`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 mr(e){let{name:t,fields:n,modulesDir:r,repo:i=`inmemory`,tokenScope:a=`app`,style:o=`define`}=e,s=e.pluralize!==!1,c=B(t),l=R(t),u=s?V(c):c,d=s?Ht(l):l,f=h(r,u),p=[],m=async(e,t)=>{let n=h(f,e);await P(n,t),p.push(n)};await m(`${c}.module.ts`,un({pascal:l,kebab:c,plural:u,repo:i,style:o})),await m(`${c}.constants.ts`,Sn({pascal:l,kebab:c})),await m(`${c}.controller.ts`,fn({pascal:l,kebab:c,plural:u,pluralPascal:d})),await m(`${c}.service.ts`,xn({pascal:l,kebab:c})),await m(`dtos/create-${c}.dto.ts`,hr(l,n)),await m(`dtos/update-${c}.dto.ts`,gr(l,n)),await m(`dtos/${c}-response.dto.ts`,_r(l,n)),await m(`${c}.repository.ts`,gn({pascal:l,kebab:c,dtoPrefix:`./dtos`,tokenScope:a}));let g=i===`inmemory`,_=g?`in-memory-${c}`:`${B(i)}-${c}`,v=g?_n({pascal:l,kebab:c,repoPrefix:`.`,dtoPrefix:`./dtos`}):vn({pascal:l,kebab:c,repoType:i,repoPrefix:`.`,dtoPrefix:`./dtos`});return await m(`${_}.repository.ts`,v),await Dn(r,l,u,c,o),p}function hr(e,t){return`import { z } from 'zod'
3188
2303
 
3189
2304
  export const create${e}Schema = z.object({
3190
2305
  ${t.map(e=>{let t=e.zodType;return` ${e.name}: ${t}${e.optional?`.optional()`:``},`}).join(`
@@ -3192,7 +2307,7 @@ ${t.map(e=>{let t=e.zodType;return` ${e.name}: ${t}${e.optional?`.optional()`:`
3192
2307
  })
3193
2308
 
3194
2309
  export type Create${e}DTO = z.infer<typeof create${e}Schema>
3195
- `}function Gr(e,t){return`import { z } from 'zod'
2310
+ `}function gr(e,t){return`import { z } from 'zod'
3196
2311
 
3197
2312
  export const update${e}Schema = z.object({
3198
2313
  ${t.map(e=>` ${e.name}: ${e.zodType}.optional(),`).join(`
@@ -3200,353 +2315,14 @@ ${t.map(e=>` ${e.name}: ${e.zodType}.optional(),`).join(`
3200
2315
  })
3201
2316
 
3202
2317
  export type Update${e}DTO = z.infer<typeof update${e}Schema>
3203
- `}function Kr(e,t){return`export interface ${e}ResponseDTO {
2318
+ `}function _r(e,t){return`export interface ${e}ResponseDTO {
3204
2319
  id: string
3205
2320
  ${t.map(e=>` ${e.name}${e.optional?`?`:``}: ${e.tsType}`).join(`
3206
2321
  `)}
3207
2322
  createdAt: string
3208
2323
  updatedAt: string
3209
2324
  }
3210
- `}function qr(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'
3211
-
3212
- export const ${e.toUpperCase()}_QUERY_CONFIG: ApiQueryParamsConfig = {
3213
- filterable: [${i}],
3214
- sortable: [${a}],
3215
- searchable: [${o}],
3216
- }
3217
- `}function Jr(e,t,n){return`import { randomUUID } from 'node:crypto'
3218
- import { Repository, HttpException } from '@forinda/kickjs'
3219
- import type { ParsedQuery } from '@forinda/kickjs'
3220
- import type { I${e}Repository } from '../../domain/repositories/${t}.repository'
3221
- import type { ${e}ResponseDTO } from '../../application/dtos/${t}-response.dto'
3222
- import type { Create${e}DTO } from '../../application/dtos/create-${t}.dto'
3223
- import type { Update${e}DTO } from '../../application/dtos/update-${t}.dto'
3224
-
3225
- @Repository()
3226
- export class InMemory${e}Repository implements I${e}Repository {
3227
- private store = new Map<string, ${e}ResponseDTO>()
3228
-
3229
- async findById(id: string): Promise<${e}ResponseDTO | null> {
3230
- return this.store.get(id) ?? null
3231
- }
3232
-
3233
- async findAll(): Promise<${e}ResponseDTO[]> {
3234
- return Array.from(this.store.values())
3235
- }
3236
-
3237
- async findPaginated(parsed: ParsedQuery): Promise<{ data: ${e}ResponseDTO[]; total: number }> {
3238
- const all = Array.from(this.store.values())
3239
- const data = all.slice(parsed.pagination.offset, parsed.pagination.offset + parsed.pagination.limit)
3240
- return { data, total: all.length }
3241
- }
3242
-
3243
- async create(dto: Create${e}DTO): Promise<${e}ResponseDTO> {
3244
- const now = new Date().toISOString()
3245
- const entity: ${e}ResponseDTO = {
3246
- id: randomUUID(),
3247
- ${n.map(e=>` ${e.name}: dto.${e.name},`).join(`
3248
- `)}
3249
- createdAt: now,
3250
- updatedAt: now,
3251
- }
3252
- this.store.set(entity.id, entity)
3253
- return entity
3254
- }
3255
-
3256
- async update(id: string, dto: Update${e}DTO): Promise<${e}ResponseDTO> {
3257
- const existing = this.store.get(id)
3258
- if (!existing) throw HttpException.notFound('${e} not found')
3259
- const updated = { ...existing, ...dto, updatedAt: new Date().toISOString() }
3260
- this.store.set(id, updated)
3261
- return updated
3262
- }
3263
-
3264
- async delete(id: string): Promise<void> {
3265
- if (!this.store.has(id)) throw HttpException.notFound('${e} not found')
3266
- this.store.delete(id)
3267
- }
3268
- }
3269
- `}function Yr(e,t,n){return`import { ${e}Id } from '../value-objects/${t}-id.vo'
3270
-
3271
- interface ${e}Props {
3272
- id: ${e}Id
3273
- ${n.map(e=>` ${e.name}${e.optional?`?`:``}: ${e.tsType}`).join(`
3274
- `)}
3275
- createdAt: Date
3276
- updatedAt: Date
3277
- }
3278
-
3279
- export class ${e} {
3280
- private constructor(private props: ${e}Props) {}
3281
-
3282
- static create(params: { ${n.filter(e=>!e.optional).map(e=>`${e.name}: ${e.tsType}`).join(`; `)} }): ${e} {
3283
- const now = new Date()
3284
- return new ${e}({
3285
- id: ${e}Id.create(),
3286
- ${n.filter(e=>!e.optional).map(e=>` ${e.name}: params.${e.name},`).join(`
3287
- `)}
3288
- createdAt: now,
3289
- updatedAt: now,
3290
- })
3291
- }
3292
-
3293
- static reconstitute(props: ${e}Props): ${e} {
3294
- return new ${e}(props)
3295
- }
3296
-
3297
- get id(): ${e}Id { return this.props.id }
3298
- ${n.map(e=>` get ${e.name}(): ${e.tsType}${e.optional?` | undefined`:``} {
3299
- return this.props.${e.name}
3300
- }`).join(`
3301
- `)}
3302
- get createdAt(): Date { return this.props.createdAt }
3303
- get updatedAt(): Date { return this.props.updatedAt }
3304
-
3305
- toJSON() {
3306
- return {
3307
- id: this.props.id.toString(),
3308
- ${n.map(e=>` ${e.name}: this.props.${e.name},`).join(`
3309
- `)}
3310
- createdAt: this.props.createdAt.toISOString(),
3311
- updatedAt: this.props.updatedAt.toISOString(),
3312
- }
3313
- }
3314
- }
3315
- `}function Xr(e){return`import { randomUUID } from 'node:crypto'
3316
-
3317
- export class ${e}Id {
3318
- private constructor(private readonly value: string) {}
3319
-
3320
- static create(): ${e}Id { return new ${e}Id(randomUUID()) }
3321
-
3322
- static from(id: string): ${e}Id {
3323
- if (!id || id.trim().length === 0) throw new Error('${e}Id cannot be empty')
3324
- return new ${e}Id(id)
3325
- }
3326
-
3327
- toString(): string { return this.value }
3328
- equals(other: ${e}Id): boolean { return this.value === other.value }
3329
- }
3330
- `}function Zr(e,t,n,r=`define`){let i=`import { ${e}Controller } from './presentation/${t}.controller'
3331
- import { ${e.toUpperCase()}_REPOSITORY } from './domain/repositories/${t}.repository'
3332
- import { InMemory${e}Repository } from './infrastructure/repositories/in-memory-${t}.repository'
3333
-
3334
- // Eagerly load decorated classes so @Service()/@Repository() decorators
3335
- // register in the DI container before the application bootstraps.
3336
- import.meta.glob(
3337
- ['./domain/services/**/*.ts', './application/use-cases/**/*.ts', '!./**/*.test.ts'],
3338
- { eager: true },
3339
- )`,a=` /**
3340
- * Declare HTTP routes for this module. Return value shape:
3341
- *
3342
- * - \`path\` — URL prefix for this route set.
3343
- * - \`controller\` — Controller class (also drives OpenAPI).
3344
- * - \`version\` — Optional. Overrides the app-wide API version.
3345
- *
3346
- * Return an array to mount multiple route sets:
3347
- *
3348
- * return [
3349
- * { path: '/${n}', version: 1, controller: ${e}V1Controller },
3350
- * { path: '/${n}', version: 2, controller: ${e}V2Controller },
3351
- * ]
3352
- */`;return r===`class`?`import { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'
3353
- ${i}
3354
-
3355
- export class ${e}Module implements AppModule {
3356
- /**
3357
- * Bind the repository token to its concrete implementation.
3358
- * Decorator-managed classes (@Service, @Controller, @Repository) are
3359
- * registered automatically — only token-to-impl bindings need to live here.
3360
- */
3361
- register(container: Container): void {
3362
- container.registerFactory(
3363
- ${e.toUpperCase()}_REPOSITORY,
3364
- () => container.resolve(InMemory${e}Repository),
3365
- )
3366
- }
3367
-
3368
- ${a.replace(/^ {4}/gm,` `).replace(/^ {6}/gm,` `)}
3369
- routes(): ModuleRoutes {
3370
- return {
3371
- path: '/${n}',
3372
- controller: ${e}Controller,
3373
- }
3374
- }
3375
- }
3376
- `:`import { defineModule } from '@forinda/kickjs'
3377
- ${i}
3378
-
3379
- export const ${e}Module = defineModule({
3380
- name: '${e}Module',
3381
- build: () => ({
3382
- /**
3383
- * Bind the repository token to its concrete implementation.
3384
- * Decorator-managed classes (@Service, @Controller, @Repository) are
3385
- * registered automatically — only token-to-impl bindings need to live here.
3386
- */
3387
- register(container) {
3388
- container.registerFactory(
3389
- ${e.toUpperCase()}_REPOSITORY,
3390
- () => container.resolve(InMemory${e}Repository),
3391
- )
3392
- },
3393
-
3394
- ${a}
3395
- routes() {
3396
- return {
3397
- path: '/${n}',
3398
- controller: ${e}Controller,
3399
- }
3400
- },
3401
- }),
3402
- })
3403
- `}function Qr(e,t,n,r){return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
3404
- import { ApiTags } from '@forinda/kickjs-swagger'
3405
- import { Create${e}UseCase } from '../application/use-cases/create-${t}.use-case'
3406
- import { Get${e}UseCase } from '../application/use-cases/get-${t}.use-case'
3407
- import { List${r}UseCase } from '../application/use-cases/list-${n}.use-case'
3408
- import { Update${e}UseCase } from '../application/use-cases/update-${t}.use-case'
3409
- import { Delete${e}UseCase } from '../application/use-cases/delete-${t}.use-case'
3410
- import { create${e}Schema } from '../application/dtos/create-${t}.dto'
3411
- import { update${e}Schema } from '../application/dtos/update-${t}.dto'
3412
- import { ${e.toUpperCase()}_QUERY_CONFIG } from '../constants'
3413
-
3414
- // Each handler annotates its \`ctx\` with \`Ctx<KickRoutes.${e}Controller['<method>']>\`
3415
- // so \`ctx.params\`, \`ctx.body\`, and \`ctx.query\` are typed end-to-end.
3416
- // The \`KickRoutes\` namespace is generated by \`kick typegen\` (auto-run on
3417
- // \`kick dev\`) — see https://forinda.github.io/kick-js/guide/typegen.
3418
-
3419
- @Controller()
3420
- export class ${e}Controller {
3421
- @Autowired() private readonly create${e}UseCase!: Create${e}UseCase
3422
- @Autowired() private readonly get${e}UseCase!: Get${e}UseCase
3423
- @Autowired() private readonly list${r}UseCase!: List${r}UseCase
3424
- @Autowired() private readonly update${e}UseCase!: Update${e}UseCase
3425
- @Autowired() private readonly delete${e}UseCase!: Delete${e}UseCase
3426
-
3427
- @Get('/')
3428
- @ApiTags('${e}')
3429
- @ApiQueryParams(${e.toUpperCase()}_QUERY_CONFIG)
3430
- async list(ctx: Ctx<KickRoutes.${e}Controller['list']>) {
3431
- return ctx.paginate(
3432
- (parsed) => this.list${r}UseCase.execute(parsed),
3433
- ${e.toUpperCase()}_QUERY_CONFIG,
3434
- )
3435
- }
3436
-
3437
- @Get('/:id')
3438
- @ApiTags('${e}')
3439
- async getById(ctx: Ctx<KickRoutes.${e}Controller['getById']>) {
3440
- const result = await this.get${e}UseCase.execute(ctx.params.id)
3441
- if (!result) return ctx.notFound('${e} not found')
3442
- ctx.json(result)
3443
- }
3444
-
3445
- @Post('/', { body: create${e}Schema, name: 'Create${e}' })
3446
- @ApiTags('${e}')
3447
- async create(ctx: Ctx<KickRoutes.${e}Controller['create']>) {
3448
- const result = await this.create${e}UseCase.execute(ctx.body)
3449
- ctx.created(result)
3450
- }
3451
-
3452
- @Put('/:id', { body: update${e}Schema, name: 'Update${e}' })
3453
- @ApiTags('${e}')
3454
- async update(ctx: Ctx<KickRoutes.${e}Controller['update']>) {
3455
- const result = await this.update${e}UseCase.execute(ctx.params.id, ctx.body)
3456
- ctx.json(result)
3457
- }
3458
-
3459
- @Delete('/:id')
3460
- @ApiTags('${e}')
3461
- async remove(ctx: Ctx<KickRoutes.${e}Controller['remove']>) {
3462
- await this.delete${e}UseCase.execute(ctx.params.id)
3463
- ctx.noContent()
3464
- }
3465
- }
3466
- `}function $r(e,t,n){return`import { createToken } from '@forinda/kickjs'
3467
- import type { ${e}ResponseDTO } from '../../application/dtos/${t}-response.dto'
3468
- import type { Create${e}DTO } from '../../application/dtos/create-${t}.dto'
3469
- import type { Update${e}DTO } from '../../application/dtos/update-${t}.dto'
3470
- import type { ParsedQuery } from '@forinda/kickjs'
3471
-
3472
- export interface I${e}Repository {
3473
- findById(id: string): Promise<${e}ResponseDTO | null>
3474
- findAll(): Promise<${e}ResponseDTO[]>
3475
- findPaginated(parsed: ParsedQuery): Promise<{ data: ${e}ResponseDTO[]; total: number }>
3476
- create(dto: Create${e}DTO): Promise<${e}ResponseDTO>
3477
- update(id: string, dto: Update${e}DTO): Promise<${e}ResponseDTO>
3478
- delete(id: string): Promise<void>
3479
- }
3480
-
3481
- /**
3482
- * Collision-safe DI token bound to \`I${e}Repository\`.
3483
- * \`container.resolve(${e.toUpperCase()}_REPOSITORY)\` and
3484
- * \`@Inject(${e.toUpperCase()}_REPOSITORY)\` both return the typed
3485
- * interface — no manual generic, no \`any\` cast.
3486
- *
3487
- * The \`'${n}/'\` prefix matches the project scope so
3488
- * \`kick-lint\`'s \`token-reserved-prefix\` rule never fires —
3489
- * adopters must NOT use the reserved \`'kick/'\` namespace.
3490
- */
3491
- export const ${e.toUpperCase()}_REPOSITORY = createToken<I${e}Repository>('${n}/${e}/repository')
3492
- `}function ei(e,t){return`import { Service, Inject, HttpException } from '@forinda/kickjs'
3493
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../repositories/${t}.repository'
3494
-
3495
- @Service()
3496
- export class ${e}DomainService {
3497
- constructor(
3498
- @Inject(${e.toUpperCase()}_REPOSITORY) private readonly repo: I${e}Repository,
3499
- ) {}
3500
-
3501
- async ensureExists(id: string): Promise<void> {
3502
- const entity = await this.repo.findById(id)
3503
- if (!entity) throw HttpException.notFound('${e} not found')
3504
- }
3505
- }
3506
- `}function ti(e,t,n,r){return[{file:`create-${t}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
3507
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
3508
- import type { Create${e}DTO } from '../dtos/create-${t}.dto'
3509
-
3510
- @Service()
3511
- export class Create${e}UseCase {
3512
- constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
3513
- async execute(dto: Create${e}DTO) { return this.repo.create(dto) }
3514
- }
3515
- `},{file:`get-${t}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
3516
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
3517
-
3518
- @Service()
3519
- export class Get${e}UseCase {
3520
- constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
3521
- async execute(id: string) { return this.repo.findById(id) }
3522
- }
3523
- `},{file:`list-${n}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
3524
- import type { ParsedQuery } from '@forinda/kickjs'
3525
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
3526
-
3527
- @Service()
3528
- export class List${r}UseCase {
3529
- constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
3530
- async execute(parsed: ParsedQuery) { return this.repo.findPaginated(parsed) }
3531
- }
3532
- `},{file:`update-${t}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
3533
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
3534
- import type { Update${e}DTO } from '../dtos/update-${t}.dto'
3535
-
3536
- @Service()
3537
- export class Update${e}UseCase {
3538
- constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
3539
- async execute(id: string, dto: Update${e}DTO) { return this.repo.update(id, dto) }
3540
- }
3541
- `},{file:`delete-${t}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
3542
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
3543
-
3544
- @Service()
3545
- export class Delete${e}UseCase {
3546
- constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
3547
- async execute(id: string) { return this.repo.delete(id) }
3548
- }
3549
- `}]}async function ni(e){let{name:t,moduleName:n,modulesDir:r}=e,i=e.pluralize??!0,a=R(t),o=I(t),s=[],c;if(e.outDir)c=v(e.outDir);else if(n){let e=R(n),t=i?z(e):e;c=v(h(r??`src/modules`,t,`__tests__`))}else c=v(`src/__tests__`);let l=h(c,`${a}.test.ts`);return await M(l,`import { describe, it, expect, beforeEach } from 'vitest'
2325
+ `}async function vr(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=v(e.outDir);else if(n){let e=B(n),t=i?V(e):e;c=v(h(r??`src/modules`,t,`__tests__`))}else c=v(`src/__tests__`);let l=h(c,`${a}.test.ts`);return await P(l,`import { describe, it, expect, beforeEach } from 'vitest'
3550
2326
  import { Container } from '@forinda/kickjs'
3551
2327
 
3552
2328
  describe('${o}', () => {
@@ -3569,9 +2345,9 @@ describe('${o}', () => {
3569
2345
  expect(true).toBe(true)
3570
2346
  })
3571
2347
  })
3572
- `),s.push(l),s}const ri=[`Service`,`Controller`,`Repository`,`Injectable`,`Component`,`Module`],ii=[`.ts`,`.tsx`,`.mts`,`.cts`],ai=[`node_modules`,`.kickjs`,`dist`,`build`,`.test.`,`.spec.`,`.d.ts`],oi=new RegExp(String.raw`@(${ri.join(`|`)})\s*\([^)]*\)`+String.raw`(?:\s*@[A-Z]\w*(?:\s*\([^)]*\))?)*`+String.raw`\s*export\s+(default\s+)?(?:abstract\s+)?class\s+(\w+)`,`g`),si=new RegExp(String.raw`export\s+(default\s+)?(?:abstract\s+)?class\s+(\w+)`+String.raw`(?:\s+extends\s+\w+(?:<[^>]*>)?)?`+String.raw`\s+implements\s+[^{]*\bAppModule\b`,`g`),ci=/(?:export\s+)?const\s+(\w+)\s*(?::\s*[^=]+)?=\s*createToken\s*(?:<[^>]*>)?\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,li=/createToken\s*(?:<[^>]*>)?\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,ui=/@Inject\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,di=/\b(defineAdapter|definePlugin)\s*(?:<[^>]*>)?\s*\(/g,fi=/\b(?:defineContextDecorator|defineHttpContextDecorator)\s*(?:\.withParams\s*<(?:[^<>]|<[^<>]*>)*>\s*\(\s*\))?\s*(?:<(?:[^<>]|<[^<>]*>)*>)?\s*\(/g,pi=new RegExp(String.raw`export\s+(?:default\s+)?(?:abstract\s+)?class\s+(\w+)`+String.raw`(?:\s+extends\s+\w+(?:<[^>]*>)?)?`+String.raw`\s+implements\s+[^{]*\bAppAdapter\b`,`g`),mi=/\bname\s*(?::\s*[^=]+)?=\s*['"`]([^'"`]+)['"`]/,hi=/\bdefineAugmentation\s*\(\s*['"`]([^'"`]+)['"`]\s*(,\s*\{)?/g,gi=new RegExp(String.raw`@(${[`Get`,`Post`,`Put`,`Delete`,`Patch`].join(`|`)})\s*\(`,`g`);function _i(e,t){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 vi(e,t){let n=t;for(;n<e.length;){for(;n<e.length&&/\s/.test(e[n]);)n++;if(e[n]!==`@`)break;let t=e.slice(n).match(/^@([A-Z]\w*)/);if(!t)break;for(n+=t[0].length;n<e.length&&/\s/.test(e[n]);)n++;if(e[n]===`(`){let t=_i(e,n);if(t<0)return null;n=t+1}}for(;n<e.length&&/\s/.test(e[n]);)n++;for(let t of[`public`,`private`,`protected`])if(e.slice(n,n+t.length)===t&&/\s/.test(e.charAt(n+t.length))){for(n+=t.length;n<e.length&&/\s/.test(e[n]);)n++;break}if(e.slice(n,n+5)===`async`&&/\s/.test(e.charAt(n+5)))for(n+=5;n<e.length&&/\s/.test(e[n]);)n++;let r=e.slice(n).match(/^([a-zA-Z_]\w*)\s*\(/);return r?{methodName:r[1],endPos:n+r[0].length}:null}function yi(e){return(e.match(/:([a-zA-Z_]\w*)/g)??[]).map(e=>e.slice(1))}function bi(e,t){let n=e.endsWith(`/`)?e.slice(0,-1):e;return!t||t===`/`?n||`/`:n+(t.startsWith(`/`)?t:`/`+t)||`/`}const xi=/\b(?:public\s+|private\s+|protected\s+)?routes\s*\([^)]*\)\s*(?::\s*[A-Za-z_][\w<>[\]\s,|]*\s*)?\{/g,Si=/\bpath\s*:\s*['"`]([^'"`]*)['"`]/g,Ci=/\bcontroller\s*:\s*([A-Z]\w*)\b/g,wi=/\bimport\.meta\.glob\s*\(/g;function Ti(e){let t=[];for(wi.lastIndex=0;wi.exec(e)!==null;){let n=wi.lastIndex-1,r=_i(e,n);if(r<0)continue;let i=e.slice(n+1,r),a=/['"`]([^'"`]+)['"`]/g,o;for(;(o=a.exec(i))!==null;)t.push(o[1])}return t}function Ei(e){let t=e.replace(/[.+^$()|[\]\\]/g,`\\$&`).replace(/\?/g,`.`).replace(/\*\*\//g,`___DOUBLESTAR_SLASH___`).replace(/\*\*/g,`___DOUBLESTAR___`).replace(/\*/g,`[^/]*`).replace(/___DOUBLESTAR_SLASH___/g,`(?:.+/)?`).replace(/___DOUBLESTAR___/g,`.*`);return RegExp(`^`+t+`$`)}function Di(e,t){let n=e.startsWith(`./`)?e:`./`+e,r=!1;for(let e of t){let t=e.startsWith(`!`);Ei(t?e.slice(1):e).test(n)&&(r=!t)}return r}function Oi(e){let t=[];xi.lastIndex=0;let n;for(;(n=xi.exec(e))!==null;){let r=e.indexOf(`{`,n.index+n[0].length-1);if(r<0)continue;let i=Bi(e,r);if(i<0)continue;let a=e.slice(r+1,i),o=[];Si.lastIndex=0;let s;for(;(s=Si.exec(a))!==null;)o.push(s[1]??``);let c=[];Ci.lastIndex=0;let l;for(;(l=Ci.exec(a))!==null;)c.push(l[1]);let u=Math.min(o.length,c.length);for(let e=0;e<u;e++)t.push({controller:c[e],mountPath:o[e]})}return t}function ki(e,t){let n=new RegExp(String.raw`\b${t}\s*:\s*([A-Za-z_$][\w$]*)`,`g`).exec(e);return n?n[1]:null}function Ai(e,t){let n=new RegExp(String.raw`import\s*(?:type\s+)?\{[^}]*\b${t}\b[^}]*\}\s*from\s*['"\`]([^'"\`]+)['"\`]`).exec(e);if(n)return n[1];let r=new RegExp(String.raw`import\s+(?:type\s+)?${t}\s+from\s*['"\`]([^'"\`]+)['"\`]`).exec(e);if(r)return r[1];let i=new RegExp(String.raw`import\s*\*\s*as\s+${t}\s+from\s*['"\`]([^'"\`]+)['"\`]`).exec(e);return i?i[1]:new RegExp(String.raw`(?:^|\n)\s*(?:export\s+)?const\s+${t}\b`).test(e)?``:null}function ji(e,t){let n=/@ApiQueryParams\s*\(\s*([\s\S]*?)\s*\)\s*$/.exec(e);if(!n){let n=/@ApiQueryParams\s*\(([\s\S]*?)\)/.exec(e);return n?Mi(n[1].trim(),t):null}return Mi(n[1].trim(),t)}function Mi(e,t){if(e.startsWith(`{`))return Pi(e);let n=/^([A-Za-z_]\w*)/.exec(e);if(n){let e=n[1],r=new RegExp(String.raw`const\s+${e}\s*(?::\s*[^=]+)?=\s*(\{[\s\S]*?\n\})`,`m`).exec(t);if(r)return Pi(r[1])}return{filterable:[],sortable:[],searchable:[]}}function Ni(e,t){let n=new RegExp(String.raw`${t}\s*:\s*\[([\s\S]*?)\]`).exec(e);return n?Array.from(n[1].matchAll(/['"`]([^'"`]+)['"`]/g)).map(e=>e[1]):[]}function Pi(e){return{filterable:Ni(e,`filterable`),sortable:Ni(e,`sortable`),searchable:Ni(e,`searchable`)}}async function Fi(e,t){let n=t.extensions??ii,r=t.exclude??ai,i=[],a;try{a=await se(e,{withFileTypes:!0,encoding:`utf-8`})}catch{return i}for(let o of a){let a=h(e,o.name),s=_(t.cwd,a);r.some(e=>s.includes(e))||(o.isDirectory()?i.push(...await Fi(a,t)):o.isFile()&&n.some(e=>o.name.endsWith(e))&&i.push(a))}return i}function G(e,t){return _(t,e).split(y).join(`/`)}function Ii(e,t,n){let r=[],i=G(t,n);oi.lastIndex=0;let a;for(;(a=oi.exec(e))!==null;){let[,e,n,o]=a;r.push({className:o,decorator:e,filePath:t,relativePath:i,isDefault:!!n})}si.lastIndex=0;let o;for(;(o=si.exec(e))!==null;){let[,e,n]=o;r.some(e=>e.className===n&&e.filePath===t)||r.push({className:n,decorator:`Module`,filePath:t,relativePath:i,isDefault:!!e})}return r}function Li(e,t,n){let r=[],i=G(t,n),a=new Set;ci.lastIndex=0;let o;for(;(o=ci.exec(e))!==null;){let[e,n,s]=o;a.add(e),r.push({name:s,variable:n,filePath:t,relativePath:i})}for(li.lastIndex=0;(o=li.exec(e))!==null;)a.has(o[0])||r.push({name:o[1],variable:null,filePath:t,relativePath:i});return r}function Ri(e,t,n,r,i=new Map){let a=[];if(r.length===0)return a;let o=G(t,n),s=[];for(let t of r){let n=new RegExp(String.raw`class\s+${t.className}\b`).exec(e);n?.index!==void 0&&s.push({cls:t,start:n.index})}s.sort((e,t)=>e.start-t.start);for(let n=0;n<s.length;n++){let{cls:r,start:c}=s[n],l=n+1<s.length?s[n+1].start:e.length,u=e.slice(c,l);gi.lastIndex=0;let d;for(;(d=gi.exec(u))!==null;){let n=d[1],s=d.index,c=gi.lastIndex-1,l=_i(u,c);if(l<0)continue;let f=u.slice(c+1,l),p=f.match(/^\s*['"`]([^'"`]*)['"`]/),m=p&&p[1].length>0?p[1]:`/`,h=vi(u,l+1);if(!h)continue;let{methodName:g,endPos:_}=h;gi.lastIndex=_;let v=ji(u.slice(s,_),e),y=ki(f,`body`),b=ki(f,`query`),x=ki(f,`params`),ee=i.get(r.className)??``,S=ee?bi(ee,m):m;a.push({controller:r.className,method:g,httpMethod:n.toUpperCase(),path:m,pathParams:yi(S),queryFilterable:v?.filterable??null,querySortable:v?.sortable??null,querySearchable:v?.searchable??null,bodySchema:y?{identifier:y,source:Ai(e,y)}:null,querySchema:b?{identifier:b,source:Ai(e,b)}:null,paramsSchema:x?{identifier:x,source:Ai(e,x)}:null,filePath:t,relativePath:o})}}return a}function zi(e,t,n){let r=[],i=G(t,n);ui.lastIndex=0;let a;for(;(a=ui.exec(e))!==null;)r.push({name:a[1],filePath:t,relativePath:i});return r}function Bi(e,t){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 Vi(e,t,n){let r=[],i=G(t,n),a=new Set;di.lastIndex=0;let o;for(;(o=di.exec(e))!==null;){let n=o[1],s=di.lastIndex-1,c=_i(e,s);if(c<0)continue;let l=e.slice(s+1,c),u=/\bname\s*:\s*['"`]([^'"`]+)['"`]/.exec(l);if(!u)continue;let d=u[1],f=`${n}::${d}::${t}`;a.has(f)||(a.add(f),r.push({kind:n===`definePlugin`?`plugin`:`adapter`,name:d,filePath:t,relativePath:i}))}pi.lastIndex=0;let s;for(;(s=pi.exec(e))!==null;){let n=s.index,o=e.indexOf(`{`,n);if(o<0)continue;let c=Bi(e,o);if(c<0)continue;let l=e.slice(o+1,c),u=mi.exec(l);if(!u)continue;let d=u[1],f=`class::${d}::${t}`;a.has(f)||(a.add(f),r.push({kind:`adapter`,name:d,filePath:t,relativePath:i}))}return r}function Hi(e,t,n){let r=[],i=G(t,n),a=new Set;for(fi.lastIndex=0;fi.exec(e)!==null;){let n=fi.lastIndex-1,o=_i(e,n);if(o<0)continue;let s=e.slice(n+1,o),c=/\bkey\s*:\s*['"`]([^'"`]+)['"`]/.exec(s);if(!c)continue;let l=c[1];a.has(l)||(a.add(l),r.push({key:l,filePath:t,relativePath:i}))}return r}function Ui(e,t,n){let r=[],i=G(t,n);hi.lastIndex=0;let a;for(;(a=hi.exec(e))!==null;){let n=a[1],o=null,s=null;if(a[2]){let t=e.indexOf(`{`,a.index+a[0].length-1);if(t>=0){let n=Bi(e,t);if(n>=0){let r=e.slice(t+1,n);o=Wi(r,`description`),s=Wi(r,`example`)}}}r.push({name:n,description:o,example:s,filePath:t,relativePath:i})}return r}function Wi(e,t){let n=RegExp(`\\b${t}\\s*:\\s*(['"\`])`,`g`).exec(e);if(!n)return null;let r=n[1],i=n.index+n[0].length,a=i,o=null;for(;a<e.length;){let t=e[a];if(t===`\\`){a+=2;continue}if(t===r){o=e.slice(i,a);break}a++}return o===null?null:o.replace(/\\(.)/g,(e,t)=>t===`n`?`
3573
- `:t===`t`?` `:t===`r`?`\r`:t)}const Gi=[`src/config/index.ts`,`src/config/env.ts`,`src/config.ts`,`src/env.ts`];async function Ki(e,t){let n=t===`src/env.ts`?Gi:[t];for(let t of n){let n=v(e,t),r;try{r=await C(n,`utf-8`)}catch{continue}if(!(!/\bdefineEnv\s*\(/.test(r)&&!/\bfrom(Zod|Valibot|Yup)\s*\(/.test(r))&&/export\s+default\b/.test(r)&&!/export\s+default\s+loadEnvFromSchema\s*\(/.test(r))return{filePath:n,relativePath:G(n,e)}}return null}function qi(e){let t=new Map;for(let n of e){let e=t.get(n.className)??[];e.push(n),t.set(n.className,e)}let n=[];for(let[e,r]of t)new Set(r.map(e=>e.filePath)).size>1&&n.push({className:e,classes:r});return n.sort((e,t)=>e.className.localeCompare(t.className)),n}async function Ji(e){let t=await Fi(v(e.root),e),n=[],r=[],i=[],a=[],o=[],s=[],c=[],l=new Map;for(let r of t){let t;try{t=await C(r,`utf-8`)}catch{continue}l.set(r,t),n.push(...Ii(t,r,e.cwd)),i.push(...Li(t,r,e.cwd)),a.push(...zi(t,r,e.cwd)),o.push(...Vi(t,r,e.cwd)),s.push(...Ui(t,r,e.cwd)),c.push(...Hi(t,r,e.cwd))}let u=new Map;for(let[,e]of l)for(let{controller:t,mountPath:n}of Oi(e))u.has(t)||u.set(t,n);for(let[t,i]of l){let a=n.filter(e=>e.filePath===t);r.push(...Ri(i,t,e.cwd,a,u))}let d=[];for(let[e,t]of l){if(!/\.module\.[mc]?[tj]sx?$/.test(e))continue;let r=Ti(t);if(r.length===0)continue;let i=e.replaceAll(y,`/`),a=i.slice(0,i.lastIndexOf(`/`));for(let t of n){if(t.decorator===`Module`)continue;let n=t.filePath.replaceAll(y,`/`);n.startsWith(a+`/`)&&n!==i&&(Di(n.slice(a.length+1),r)||d.push({className:t.className,filePath:t.filePath,relativePath:t.relativePath,moduleFilePath:e,decorator:t.decorator}))}}n.sort((e,t)=>e.className===t.className?e.relativePath.localeCompare(t.relativePath):e.className.localeCompare(t.className)),i.sort((e,t)=>e.name.localeCompare(t.name)||e.relativePath.localeCompare(t.relativePath)),a.sort((e,t)=>e.name.localeCompare(t.name)||e.relativePath.localeCompare(t.relativePath)),r.sort((e,t)=>e.controller.localeCompare(t.controller)||e.method.localeCompare(t.method)),o.sort((e,t)=>e.name.localeCompare(t.name)||e.relativePath.localeCompare(t.relativePath)),s.sort((e,t)=>e.name.localeCompare(t.name)||e.relativePath.localeCompare(t.relativePath)),c.sort((e,t)=>e.key.localeCompare(t.key)||e.relativePath.localeCompare(t.relativePath));let f=qi(n),p=await Ki(e.cwd,e.envFile??`src/env.ts`);return d.sort((e,t)=>e.relativePath.localeCompare(t.relativePath)||e.className.localeCompare(t.className)),{classes:n,routes:r,tokens:i,injects:a,collisions:f,env:p,pluginsAndAdapters:o,augmentations:s,contextKeys:c,orphanedClasses:d}}const K="/* 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",Yi=new Set([`Service`,`Repository`,`Injectable`,`Component`]);var Xi=class extends Error{collisions;constructor(e){super(Zi(e)),this.name=`TokenCollisionError`,this.collisions=e}};function Zi(e){let t=[`kick typegen: token collision detected`];for(let n of e){t.push(``),t.push(` ${n.classes.length} classes named '${n.className}':`);for(let e of n.classes)t.push(` - ${e.relativePath}`)}return t.push(``),t.push(`Resolutions:`),t.push(` (a) Rename one of the classes`),t.push(` (b) Use createToken<T>('namespaced/Name') and import the token explicitly — see @forinda/kickjs`),t.push(` (c) Pass --allow-duplicates to namespace the registry keys automatically`),t.push(` (e.g. 'modules/users/UserService' instead of 'UserService')`),t.join(`
3574
- `)}function Qi(e,t){let n=_(f(t),e).split(y).join(`/`);return n=n.replace(/\.(ts|tsx|mts|cts)$/i,``),n.startsWith(`.`)||(n=`./`+n),n}function $i(e){let t=e.relativePath.replace(/^src\//,``).replace(/\.(ts|tsx|mts|cts)$/i,``).split(`/`);t.pop();let n=t.join(`/`);return n?`${n}/${e.className}`:e.className}function ea(e,t,n){let r=new Set,i=[];for(let a of e){if(!Yi.has(a.decorator))continue;let e=n.has(a.className)?$i(a):a.className;if(r.has(e))continue;r.add(e);let o=Qi(a.filePath,t),s=a.isDefault?`import('${o}').default`:`import('${o}').${a.className}`;i.push(` '${e}': ${s}`)}return`${K}
2348
+ `),s.push(l),s}const yr=[`classes`,`tokens`,`injects`,`pluginsAndAdapters`,`augmentations`,`contextKeys`,`routes`,`moduleMounts`,`globPatterns`];function br(e){if(!e||typeof e!=`object`)return!1;let t=e;return yr.every(e=>Array.isArray(t[e]))}var xr=class e{path;prev;next=new Map;nextSig=new Map;constructor(e,t){this.path=e,this.prev=t}static async load(t){let n=h(t,`scan.json`),r=new Map;try{let e=await T(n,`utf-8`),t=JSON.parse(e);if(t.version===1&&t.files)for(let[e,n]of Object.entries(t.files))n&&typeof n.sig==`string`&&br(n.extract)&&r.set(e,n)}catch{}return new e(n,r)}static async signature(e){try{let t=await se(e);return`${t.mtimeMs}:${t.size}`}catch{return null}}get(e,t){let n=this.prev.get(e);return n&&n.sig===t?n.extract:null}set(e,t,n){this.next.set(e,n),this.nextSig.set(e,t)}cachedFiles(){return[...this.prev.keys()]}peek(e){return this.prev.get(e)?.extract??null}carry(e){let t=this.prev.get(e);return t?(this.next.set(e,t.extract),this.nextSig.set(e,t.sig),!0):!1}async save(){let e={};for(let[t,n]of this.next){let r=this.nextSig.get(t);r&&(e[t]={sig:r,extract:n})}let t={version:1,files:e};try{await w(f(this.path),{recursive:!0}),await E(this.path,JSON.stringify(t),`utf-8`)}catch{}}};const Sr=[`Service`,`Controller`,`Repository`,`Injectable`,`Component`,`Module`],Cr=[`.ts`,`.tsx`,`.mts`,`.cts`],wr=[`node_modules`,`.kickjs`,`dist`,`build`,`.test.`,`.spec.`,`.d.ts`],Tr=new RegExp(String.raw`@(${Sr.join(`|`)})\s*\([^)]*\)`+String.raw`(?:\s*@[A-Z]\w*(?:\s*\([^)]*\))?)*`+String.raw`\s*export\s+(default\s+)?(?:abstract\s+)?class\s+(\w+)`,`g`),Er=new RegExp(String.raw`export\s+(default\s+)?(?:abstract\s+)?class\s+(\w+)`+String.raw`(?:\s+extends\s+\w+(?:<[^>]*>)?)?`+String.raw`\s+implements\s+[^{]*\bAppModule\b`,`g`),Dr=/export\s+const\s+(\w+)\s*(?::\s*[^=]+)?=\s*defineModule\s*(?:<[^>]*>)?\s*\(/g,Or=/(?:export\s+)?const\s+(\w+)\s*(?::\s*[^=]+)?=\s*createToken\s*(?:<[^>]*>)?\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,kr=/createToken\s*(?:<[^>]*>)?\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,Ar=/@Inject\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,jr=/\b(defineAdapter|definePlugin)\s*(?:<[^>]*>)?\s*\(/g,Mr=/\b(?:defineContextDecorator|defineHttpContextDecorator)\s*(?:\.withParams\s*<(?:[^<>]|<[^<>]*>)*>\s*\(\s*\))?\s*(?:<(?:[^<>]|<[^<>]*>)*>)?\s*\(/g,Nr=new RegExp(String.raw`export\s+(?:default\s+)?(?:abstract\s+)?class\s+(\w+)`+String.raw`(?:\s+extends\s+\w+(?:<[^>]*>)?)?`+String.raw`\s+implements\s+[^{]*\bAppAdapter\b`,`g`),Pr=/\bname\s*(?::\s*[^=]+)?=\s*['"`]([^'"`]+)['"`]/,Fr=/\bdefineAugmentation\s*\(\s*['"`]([^'"`]+)['"`]\s*(,\s*\{)?/g,Ir=new RegExp(String.raw`@(${[`Get`,`Post`,`Put`,`Delete`,`Patch`].join(`|`)})\s*\(`,`g`);function Lr(e,t){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 Rr(e,t){let n=t;for(;n<e.length;){for(;n<e.length&&/\s/.test(e[n]);)n++;if(e[n]!==`@`)break;let t=e.slice(n).match(/^@([A-Z]\w*)/);if(!t)break;for(n+=t[0].length;n<e.length&&/\s/.test(e[n]);)n++;if(e[n]===`(`){let t=Lr(e,n);if(t<0)return null;n=t+1}}for(;n<e.length&&/\s/.test(e[n]);)n++;for(let t of[`public`,`private`,`protected`])if(e.slice(n,n+t.length)===t&&/\s/.test(e.charAt(n+t.length))){for(n+=t.length;n<e.length&&/\s/.test(e[n]);)n++;break}if(e.slice(n,n+5)===`async`&&/\s/.test(e.charAt(n+5)))for(n+=5;n<e.length&&/\s/.test(e[n]);)n++;let r=e.slice(n).match(/^([a-zA-Z_]\w*)\s*\(/);return r?{methodName:r[1],endPos:n+r[0].length}:null}function zr(e){return(e.match(/:([a-zA-Z_]\w*)/g)??[]).map(e=>e.slice(1))}function Br(e,t){let n=e.endsWith(`/`)?e.slice(0,-1):e;return!t||t===`/`?n||`/`:n+(t.startsWith(`/`)?t:`/`+t)||`/`}const Vr=/\b(?:public\s+|private\s+|protected\s+)?routes\s*\([^)]*\)\s*(?::\s*[A-Za-z_][\w<>[\]\s,|]*\s*)?\{/g,Hr=/\bpath\s*:\s*['"`]([^'"`]*)['"`]/g,Ur=/\bcontroller\s*:\s*([A-Z]\w*)\b/g,Wr=/\bimport\.meta\.glob\s*\(/g;function Gr(e){let t=[];for(Wr.lastIndex=0;Wr.exec(e)!==null;){let n=Wr.lastIndex-1,r=Lr(e,n);if(r<0)continue;let i=e.slice(n+1,r),a=/['"`]([^'"`]+)['"`]/g,o;for(;(o=a.exec(i))!==null;)t.push(o[1])}return t}function Kr(e){let t=e.replace(/[.+^$()|[\]\\]/g,`\\$&`).replace(/\?/g,`.`).replace(/\*\*\//g,`___DOUBLESTAR_SLASH___`).replace(/\*\*/g,`___DOUBLESTAR___`).replace(/\*/g,`[^/]*`).replace(/___DOUBLESTAR_SLASH___/g,`(?:.+/)?`).replace(/___DOUBLESTAR___/g,`.*`);return RegExp(`^`+t+`$`)}function qr(e,t){let n=e.startsWith(`./`)?e:`./`+e,r=!1;for(let e of t){let t=e.startsWith(`!`);Kr(t?e.slice(1):e).test(n)&&(r=!t)}return r}function Jr(e){let t=[];Vr.lastIndex=0;let n;for(;(n=Vr.exec(e))!==null;){let r=e.indexOf(`{`,n.index+n[0].length-1);if(r<0)continue;let i=oi(e,r);if(i<0)continue;let a=e.slice(r+1,i),o=[];Hr.lastIndex=0;let s;for(;(s=Hr.exec(a))!==null;)o.push(s[1]??``);let c=[];Ur.lastIndex=0;let l;for(;(l=Ur.exec(a))!==null;)c.push(l[1]);let u=Math.min(o.length,c.length);for(let e=0;e<u;e++)t.push({controller:c[e],mountPath:o[e]})}return t}function Yr(e,t){let n=new RegExp(String.raw`\b${t}\s*:\s*([A-Za-z_$][\w$]*)`,`g`).exec(e);return n?n[1]:null}function Xr(e,t){let n=new RegExp(String.raw`import\s*(?:type\s+)?\{[^}]*\b${t}\b[^}]*\}\s*from\s*['"\`]([^'"\`]+)['"\`]`).exec(e);if(n)return n[1];let r=new RegExp(String.raw`import\s+(?:type\s+)?${t}\s+from\s*['"\`]([^'"\`]+)['"\`]`).exec(e);if(r)return r[1];let i=new RegExp(String.raw`import\s*\*\s*as\s+${t}\s+from\s*['"\`]([^'"\`]+)['"\`]`).exec(e);return i?i[1]:new RegExp(String.raw`(?:^|\n)\s*(?:export\s+)?const\s+${t}\b`).test(e)?``:null}function Zr(e,t){let n=/@ApiQueryParams\s*\(\s*([\s\S]*?)\s*\)\s*$/.exec(e);if(!n){let n=/@ApiQueryParams\s*\(([\s\S]*?)\)/.exec(e);return n?Qr(n[1].trim(),t):null}return Qr(n[1].trim(),t)}function Qr(e,t){if(e.startsWith(`{`))return ei(e);let n=/^([A-Za-z_]\w*)/.exec(e);if(n){let e=n[1],r=new RegExp(String.raw`const\s+${e}\s*(?::\s*[^=]+)?=\s*(\{[\s\S]*?\n\})`,`m`).exec(t);if(r)return ei(r[1])}return{filterable:[],sortable:[],searchable:[]}}function $r(e,t){let n=new RegExp(String.raw`${t}\s*:\s*\[([\s\S]*?)\]`).exec(e);return n?Array.from(n[1].matchAll(/['"`]([^'"`]+)['"`]/g)).map(e=>e[1]):[]}function ei(e){return{filterable:$r(e,`filterable`),sortable:$r(e,`sortable`),searchable:$r(e,`searchable`)}}async function ti(e,t){let n=t.extensions??Cr,r=t.exclude??wr,i=[],a;try{a=await ae(e,{withFileTypes:!0,encoding:`utf-8`})}catch{return i}for(let o of a){let a=h(e,o.name),s=_(t.cwd,a);r.some(e=>s.includes(e))||(o.isDirectory()?i.push(...await ti(a,t)):o.isFile()&&n.some(e=>o.name.endsWith(e))&&i.push(a))}return i}function K(e,t){return _(t,e).split(y).join(`/`)}function ni(e,t,n){let r=[],i=K(t,n);Tr.lastIndex=0;let a;for(;(a=Tr.exec(e))!==null;){let[,e,n,o]=a;r.push({className:o,decorator:e,filePath:t,relativePath:i,isDefault:!!n})}Er.lastIndex=0;let o;for(;(o=Er.exec(e))!==null;){let[,e,n]=o;r.some(e=>e.className===n&&e.filePath===t)||r.push({className:n,decorator:`Module`,filePath:t,relativePath:i,isDefault:!!e})}Dr.lastIndex=0;let s;for(;(s=Dr.exec(e))!==null;){let[,e]=s;r.some(n=>n.className===e&&n.filePath===t)||r.push({className:e,decorator:`Module`,filePath:t,relativePath:i,isDefault:!1})}return r}function ri(e,t,n){let r=[],i=K(t,n),a=new Set;Or.lastIndex=0;let o;for(;(o=Or.exec(e))!==null;){let[e,n,s]=o;a.add(e),r.push({name:s,variable:n,filePath:t,relativePath:i})}for(kr.lastIndex=0;(o=kr.exec(e))!==null;)a.has(o[0])||r.push({name:o[1],variable:null,filePath:t,relativePath:i});return r}function ii(e,t,n,r,i=new Map){let a=[];if(r.length===0)return a;let o=K(t,n),s=[];for(let t of r){let n=new RegExp(String.raw`class\s+${t.className}\b`).exec(e);n?.index!==void 0&&s.push({cls:t,start:n.index})}s.sort((e,t)=>e.start-t.start);for(let n=0;n<s.length;n++){let{cls:r,start:c}=s[n],l=n+1<s.length?s[n+1].start:e.length,u=e.slice(c,l);Ir.lastIndex=0;let d;for(;(d=Ir.exec(u))!==null;){let n=d[1],s=d.index,c=Ir.lastIndex-1,l=Lr(u,c);if(l<0)continue;let f=u.slice(c+1,l),p=f.match(/^\s*['"`]([^'"`]*)['"`]/),m=p&&p[1].length>0?p[1]:`/`,h=Rr(u,l+1);if(!h)continue;let{methodName:g,endPos:_}=h;Ir.lastIndex=_;let v=Zr(u.slice(s,_),e),y=Yr(f,`body`),b=Yr(f,`query`),x=Yr(f,`params`),S=i.get(r.className)??``,C=S?Br(S,m):m;a.push({controller:r.className,method:g,httpMethod:n.toUpperCase(),path:m,pathParams:zr(C),queryFilterable:v?.filterable??null,querySortable:v?.sortable??null,querySearchable:v?.searchable??null,bodySchema:y?{identifier:y,source:Xr(e,y)}:null,querySchema:b?{identifier:b,source:Xr(e,b)}:null,paramsSchema:x?{identifier:x,source:Xr(e,x)}:null,filePath:t,relativePath:o})}}return a}function ai(e,t,n){let r=[],i=K(t,n);Ar.lastIndex=0;let a;for(;(a=Ar.exec(e))!==null;)r.push({name:a[1],filePath:t,relativePath:i});return r}function oi(e,t){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 si(e,t,n){let r=[],i=K(t,n),a=new Set;jr.lastIndex=0;let o;for(;(o=jr.exec(e))!==null;){let n=o[1],s=jr.lastIndex-1,c=Lr(e,s);if(c<0)continue;let l=e.slice(s+1,c),u=/\bname\s*:\s*['"`]([^'"`]+)['"`]/.exec(l);if(!u)continue;let d=u[1],f=`${n}::${d}::${t}`;a.has(f)||(a.add(f),r.push({kind:n===`definePlugin`?`plugin`:`adapter`,name:d,filePath:t,relativePath:i}))}Nr.lastIndex=0;let s;for(;(s=Nr.exec(e))!==null;){let n=s.index,o=e.indexOf(`{`,n);if(o<0)continue;let c=oi(e,o);if(c<0)continue;let l=e.slice(o+1,c),u=Pr.exec(l);if(!u)continue;let d=u[1],f=`class::${d}::${t}`;a.has(f)||(a.add(f),r.push({kind:`adapter`,name:d,filePath:t,relativePath:i}))}return r}function ci(e,t,n){let r=[],i=K(t,n),a=new Set;for(Mr.lastIndex=0;Mr.exec(e)!==null;){let n=Mr.lastIndex-1,o=Lr(e,n);if(o<0)continue;let s=e.slice(n+1,o),c=/\bkey\s*:\s*['"`]([^'"`]+)['"`]/.exec(s);if(!c)continue;let l=c[1];a.has(l)||(a.add(l),r.push({key:l,filePath:t,relativePath:i}))}return r}function li(e,t,n){let r=[],i=K(t,n);Fr.lastIndex=0;let a;for(;(a=Fr.exec(e))!==null;){let n=a[1],o=null,s=null;if(a[2]){let t=e.indexOf(`{`,a.index+a[0].length-1);if(t>=0){let n=oi(e,t);if(n>=0){let r=e.slice(t+1,n);o=ui(r,`description`),s=ui(r,`example`)}}}r.push({name:n,description:o,example:s,filePath:t,relativePath:i})}return r}function ui(e,t){let n=RegExp(`\\b${t}\\s*:\\s*(['"\`])`,`g`).exec(e);if(!n)return null;let r=n[1],i=n.index+n[0].length,a=i,o=null;for(;a<e.length;){let t=e[a];if(t===`\\`){a+=2;continue}if(t===r){o=e.slice(i,a);break}a++}return o===null?null:o.replace(/\\(.)/g,(e,t)=>t===`n`?`
2349
+ `:t===`t`?` `:t===`r`?`\r`:t)}const di=[`src/config/index.ts`,`src/config/env.ts`,`src/config.ts`,`src/env.ts`];async function fi(e,t){let n=t===`src/env.ts`?di:[t];for(let t of n){let n=v(e,t),r;try{r=await T(n,`utf-8`)}catch{continue}if(!(!/\bdefineEnv\s*\(/.test(r)&&!/\bfrom(Zod|Valibot|Yup)\s*\(/.test(r))&&/export\s+default\b/.test(r)&&!/export\s+default\s+loadEnvFromSchema\s*\(/.test(r))return{filePath:n,relativePath:K(n,e)}}return null}function pi(e){let t=new Map;for(let n of e){let e=t.get(n.className)??[];e.push(n),t.set(n.className,e)}let n=[];for(let[e,r]of t)new Set(r.map(e=>e.filePath)).size>1&&n.push({className:e,classes:r});return n.sort((e,t)=>e.className.localeCompare(t.className)),n}function mi(e,t,n){let r=ni(e,t,n);return{classes:r,tokens:ri(e,t,n),injects:ai(e,t,n),pluginsAndAdapters:si(e,t,n),augmentations:li(e,t,n),contextKeys:ci(e,t,n),routes:ii(e,t,n,r,new Map),moduleMounts:Jr(e),globPatterns:/\.module\.[mc]?[tj]sx?$/.test(t)?Gr(e):[]}}async function hi(e,t,n){let r=n?await xr.signature(e):null;if(n&&r){let t=n.get(e,r);if(t)return n.set(e,r,t),t}let i;try{i=await T(e,`utf-8`)}catch{return null}let a=mi(i,e,t);return n&&r&&n.set(e,r,a),a}async function gi(e,t,n){let r=[],i=0,a=Array.from({length:Math.min(t,e.length)},async()=>{for(;;){let t=i++;if(t>=e.length)return;r[t]=await n(e[t],t)}});return await Promise.all(a),r}async function _i(e){let t=(await ti(v(e.root),e)).toSorted(),n=e.cacheDir?await xr.load(e.cacheDir):null,r=bi(t,await gi(t,16,t=>hi(t,e.cwd,n))),i=await fi(e.cwd,e.envFile??`src/env.ts`);return n&&await n.save(),{...r,env:i}}function vi(e,t,n){let r=n.extensions??Cr,i=n.exclude??wr;if(!e.startsWith(t+y)&&e!==t||!r.some(t=>e.endsWith(t)))return!1;let a=_(n.cwd,e);return!i.some(e=>a.includes(e))}async function yi(e,t){if(!e.cacheDir)return _i(e);let n=v(e.root),r=await xr.load(e.cacheDir),i=r.cachedFiles();if(i.length===0)return _i(e);let a=new Set(t.removed.map(t=>v(e.cwd,t))),o=t.changed.map(t=>v(e.cwd,t)).filter(t=>!a.has(t)&&vi(t,n,e)),s=new Set(o),c=new Set(i);for(let e of s)c.add(e);for(let e of a)c.delete(e);let l=new Map;await gi(o,16,async t=>{if(!c.has(t))return;let n=await xr.signature(t),i;try{i=await T(t,`utf-8`)}catch{c.delete(t);return}let a=mi(i,t,e.cwd);l.set(t,a),n&&r.set(t,n,a)});let u=[...c].toSorted(),d=bi(u,u.map(e=>l.get(e)||(r.carry(e),r.peek(e)))),f=await fi(e.cwd,e.envFile??`src/env.ts`);return await r.save(),{...d,env:f}}function bi(e,t){let n=[],r=[],i=[],a=[],o=[],s=[],c=[],l=new Map;for(let e of t)if(e)for(let{controller:t,mountPath:n}of e.moduleMounts)l.has(t)||l.set(t,n);let u=new Map;for(let d=0;d<e.length;d++){let f=t[d];if(f){n.push(...f.classes),i.push(...f.tokens),a.push(...f.injects),o.push(...f.pluginsAndAdapters),s.push(...f.augmentations),c.push(...f.contextKeys),f.globPatterns.length>0&&u.set(e[d],f.globPatterns);for(let e of f.routes){let t=l.get(e.controller);if(t){let n=Br(t,e.path);r.push({...e,pathParams:zr(n)})}else r.push(e)}}}let d=[];for(let[e,t]of u){if(!/\.module\.[mc]?[tj]sx?$/.test(e)||t.length===0)continue;let r=e.replaceAll(y,`/`),i=r.slice(0,r.lastIndexOf(`/`));for(let a of n){if(a.decorator===`Module`)continue;let n=a.filePath.replaceAll(y,`/`);n.startsWith(i+`/`)&&n!==r&&(qr(n.slice(i.length+1),t)||d.push({className:a.className,filePath:a.filePath,relativePath:a.relativePath,moduleFilePath:e,decorator:a.decorator}))}}n.sort((e,t)=>e.className===t.className?e.relativePath.localeCompare(t.relativePath):e.className.localeCompare(t.className)),i.sort((e,t)=>e.name.localeCompare(t.name)||e.relativePath.localeCompare(t.relativePath)),a.sort((e,t)=>e.name.localeCompare(t.name)||e.relativePath.localeCompare(t.relativePath)),r.sort((e,t)=>e.controller.localeCompare(t.controller)||e.method.localeCompare(t.method)),o.sort((e,t)=>e.name.localeCompare(t.name)||e.relativePath.localeCompare(t.relativePath)),s.sort((e,t)=>e.name.localeCompare(t.name)||e.relativePath.localeCompare(t.relativePath)),c.sort((e,t)=>e.key.localeCompare(t.key)||e.relativePath.localeCompare(t.relativePath));let f=pi(n);return d.sort((e,t)=>e.relativePath.localeCompare(t.relativePath)||e.className.localeCompare(t.className)),{classes:n,routes:r,tokens:i,injects:a,collisions:f,pluginsAndAdapters:o,augmentations:s,contextKeys:c,orphanedClasses:d}}const q="/* 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",xi=new Set([`Service`,`Repository`,`Injectable`,`Component`]);var Si=class extends Error{collisions;constructor(e){super(Ci(e)),this.name=`TokenCollisionError`,this.collisions=e}};function Ci(e){let t=[`kick typegen: token collision detected`];for(let n of e){t.push(``),t.push(` ${n.classes.length} classes named '${n.className}':`);for(let e of n.classes)t.push(` - ${e.relativePath}`)}return t.push(``),t.push(`Resolutions:`),t.push(` (a) Rename one of the classes`),t.push(` (b) Use createToken<T>('namespaced/Name') and import the token explicitly — see @forinda/kickjs`),t.push(` (c) Pass --allow-duplicates to namespace the registry keys automatically`),t.push(` (e.g. 'modules/users/UserService' instead of 'UserService')`),t.join(`
2350
+ `)}function wi(e,t){let n=_(f(t),e).split(y).join(`/`);return n=n.replace(/\.(ts|tsx|mts|cts)$/i,``),n.startsWith(`.`)||(n=`./`+n),n}function Ti(e){let t=e.relativePath.replace(/^src\//,``).replace(/\.(ts|tsx|mts|cts)$/i,``).split(`/`);t.pop();let n=t.join(`/`);return n?`${n}/${e.className}`:e.className}function Ei(e,t,n){let r=new Set,i=[];for(let a of e){if(!xi.has(a.decorator))continue;let e=n.has(a.className)?Ti(a):a.className;if(r.has(e))continue;r.add(e);let o=wi(a.filePath,t),s=a.isDefault?`import('${o}').default`:`import('${o}').${a.className}`;i.push(` '${e}': ${s}`)}return`${q}
3575
2351
  declare module '@forinda/kickjs' {
3576
2352
  interface KickJsRegistry {
3577
2353
  ${i.length?i.join(`
@@ -3580,7 +2356,7 @@ ${i.length?i.join(`
3580
2356
  }
3581
2357
 
3582
2358
  export {}
3583
- `}function ta(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)}function na(e){return`${K}
2359
+ `}function Di(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)}function Oi(e){return`${q}
3584
2360
  declare module '@forinda/kickjs' {
3585
2361
  /**
3586
2362
  * Key-only registry of every context key produced by a
@@ -3589,20 +2365,20 @@ declare module '@forinda/kickjs' {
3589
2365
  * \`ContextMeta\`; this only records that the key exists.
3590
2366
  */
3591
2367
  interface ContextKeys {
3592
- ${[...new Set(e.map(e=>e.key))].toSorted().map(e=>` ${ta(e)?e:JSON.stringify(e)}: true`).join(`
2368
+ ${[...new Set(e.map(e=>e.key))].toSorted().map(e=>` ${Di(e)?e:JSON.stringify(e)}: true`).join(`
3593
2369
  `)}
3594
2370
  }
3595
2371
  }
3596
2372
 
3597
2373
  export {}
3598
- `}function ra(e,t,n){return t.length===0?`${K}
2374
+ `}function ki(e,t,n){return t.length===0?`${q}
3599
2375
  // ${n}
3600
2376
  export type ${e} = never
3601
- `:`${K}
2377
+ `:`${q}
3602
2378
  export type ${e} =
3603
2379
  ${[...new Set(t)].toSorted().map(e=>` | '${e}'`).join(`
3604
2380
  `)}
3605
- `}function ia(e,t,n,r){return[...e.filter(e=>Yi.has(e.decorator)).map(e=>r.has(e.className)?$i(e):e.className),...t.map(e=>e.name),...n.map(e=>e.name)]}function aa(e){return e.filter(e=>e.decorator===`Module`).map(e=>e.className)}function oa(e){let t=new Map;for(let n of e)t.has(n.name)||t.set(n.name,n);return`${K}
2381
+ `}function Ai(e,t,n,r){return[...e.filter(e=>xi.has(e.decorator)).map(e=>r.has(e.className)?Ti(e):e.className),...t.map(e=>e.name),...n.map(e=>e.name)]}function ji(e){return e.filter(e=>e.decorator===`Module`).map(e=>e.className)}function Mi(e){let t=new Map;for(let n of e)t.has(n.name)||t.set(n.name,n);return`${q}
3606
2382
  declare module '@forinda/kickjs' {
3607
2383
  /**
3608
2384
  * Map of every plugin/adapter \`name\` discovered in the project. The
@@ -3617,7 +2393,7 @@ ${[...t.values()].toSorted((e,t)=>e.name.localeCompare(t.name)).map(e=>` '${e
3617
2393
  }
3618
2394
 
3619
2395
  export {}
3620
- `}function sa(e){if(e.length===0)return`${K}
2396
+ `}function Ni(e){if(e.length===0)return`${q}
3621
2397
  // No augmentations discovered.
3622
2398
  //
3623
2399
  // Plugins advertise augmentable interfaces via:
@@ -3633,7 +2409,7 @@ export {}
3633
2409
  `;let t=new Map;for(let n of e)t.has(n.name)||t.set(n.name,n);let n=[];for(let e of[...t.values()].toSorted((e,t)=>e.name.localeCompare(t.name))){let t=[];if(e.description)for(let n of e.description.split(`
3634
2410
  `))t.push(` * ${n}`);if(e.example){t.push(` * @example`," * ```ts");for(let n of e.example.split(`
3635
2411
  `))t.push(` * ${n}`);t.push(" * ```")}t.push(` * @see ${e.relativePath}`),n.push([`/**`,...t,` */`,`export interface ${e.name}Augmentation {}`].join(`
3636
- `))}return`${K}
2412
+ `))}return`${q}
3637
2413
  // Catalogue of augmentable interfaces in this project. The interfaces
3638
2414
  // below are documentation only — augment the source-of-truth interfaces
3639
2415
  // in your own \`d.ts\` files (the framework declares the actual types).
@@ -3641,7 +2417,7 @@ export {}
3641
2417
  ${n.join(`
3642
2418
 
3643
2419
  `)}
3644
- `}const ca=/^(kick\/)?([a-z][\w-]*\/[A-Z]\w*)(\/.+)?(:[a-z][\w-]+(:[a-z][\w-]+)*)?$/;function la(e){let t=[];for(let n of e){let e=n.name;e.startsWith(`kickjs.`)||ca.test(e)||t.push({token:e,variable:n.variable,filePath:n.relativePath,reason:"does not match `<scope>/<PascalKey>[/<suffix>][:<instance>]`",suggestion:ua(e)})}return t}function ua(e){if(/^[A-Z]\w*$/.test(e))return`'<scope>/${e}' (e.g. 'mycorp/${e}')`;if(e.includes(`.`))return`consider '<scope>/PascalKey' instead of dotted form`;let t=/^([a-z][\w-]*)\/([a-z]\w*)$/.exec(e);if(t){let[,e,n]=t;return`'${e}/${n.charAt(0).toUpperCase()}${n.slice(1)}'`}}function da(e,t){if(!e)return{entries:[],count:0};let n=new Map;for(let[r,i]of Object.entries(e)){if(!i||typeof i.src!=`string`)continue;let e=v(t,i.src);if(!ga(e))continue;let a=pe(i.glob??`**/*`,{cwd:e,nodir:!0,dot:!1,posix:!0});a.sort();let{pairs:o}=me(r,a,{strategy:i.keys??`auto`});for(let{key:e}of o){let t=e.slice(r.length+1);n.set(e,{namespace:r,key:t})}}return{entries:[...n.values()],count:n.size}}function fa(e){let t="/* 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";if(e.entries.length===0)return`${t}
2420
+ `}const Pi=/^(kick\/)?([a-z][\w-]*\/[A-Z]\w*)(\/.+)?(:[a-z][\w-]+(:[a-z][\w-]+)*)?$/;function Fi(e){let t=[];for(let n of e){let e=n.name;e.startsWith(`kickjs.`)||Pi.test(e)||t.push({token:e,variable:n.variable,filePath:n.relativePath,reason:"does not match `<scope>/<PascalKey>[/<suffix>][:<instance>]`",suggestion:Ii(e)})}return t}function Ii(e){if(/^[A-Z]\w*$/.test(e))return`'<scope>/${e}' (e.g. 'mycorp/${e}')`;if(e.includes(`.`))return`consider '<scope>/PascalKey' instead of dotted form`;let t=/^([a-z][\w-]*)\/([a-z]\w*)$/.exec(e);if(t){let[,e,n]=t;return`'${e}/${n.charAt(0).toUpperCase()}${n.slice(1)}'`}}function Li(e,t){if(!e)return{entries:[],count:0};let n=new Map;for(let[r,i]of Object.entries(e)){if(!i||typeof i.src!=`string`)continue;let e=v(t,i.src);if(!Hi(e))continue;let a=fe(i.glob??`**/*`,{cwd:e,nodir:!0,dot:!1,posix:!0});a.sort();let{pairs:o}=pe(r,a,{strategy:i.keys??`auto`});for(let{key:e}of o){let t=e.slice(r.length+1);n.set(e,{namespace:r,key:t})}}return{entries:[...n.values()],count:n.size}}function Ri(e){let t="/* 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";if(e.entries.length===0)return`${t}
3645
2421
  declare module '@forinda/kickjs' {
3646
2422
  /**
3647
2423
  * Map of every typed asset discovered in the project's assetMap.
@@ -3652,7 +2428,7 @@ declare module '@forinda/kickjs' {
3652
2428
  }
3653
2429
 
3654
2430
  export {}
3655
- `;let n={};for(let t of e.entries){let e=`${t.namespace}/${t.key}`.split(`/`),r=n;for(let t=0;t<e.length-1;t++){let n=e[t],i=r[n];if(i===pa){let e={};r[n]=e,r=e}else i||(r[n]={}),r=r[n]}let i=e[e.length-1];typeof r[i]!=`object`&&(r[i]=pa)}return`${t}
2431
+ `;let n={};for(let t of e.entries){let e=`${t.namespace}/${t.key}`.split(`/`),r=n;for(let t=0;t<e.length-1;t++){let n=e[t],i=r[n];if(i===zi){let e={};r[n]=e,r=e}else i||(r[n]={}),r=r[n]}let i=e[e.length-1];typeof r[i]!=`object`&&(r[i]=zi)}return`${t}
3656
2432
  declare module '@forinda/kickjs' {
3657
2433
  /**
3658
2434
  * Map of every typed asset discovered in the project's assetMap.
@@ -3661,71 +2437,71 @@ declare module '@forinda/kickjs' {
3661
2437
  * prod → dist).
3662
2438
  */
3663
2439
  interface KickAssets {
3664
- ${ma(n,` `)}
2440
+ ${Bi(n,` `)}
3665
2441
  }
3666
2442
  }
3667
2443
 
3668
2444
  export {}
3669
- `}const pa=Symbol(`asset-leaf`);function ma(e,t){let n=Object.keys(e).toSorted(),r=[];for(let i of n){let n=e[i],a=ha(i)?i:JSON.stringify(i);n===pa?r.push(`${t}${a}: () => string`):(r.push(`${t}${a}: {`),r.push(ma(n,`${t} `)),r.push(`${t}}`))}return r.join(`
3670
- `)}function ha(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)}function ga(e){try{return c(e).isDirectory()}catch{return!1}}var _a=D({runTypegen:()=>q,sweepStaleTypegen:()=>Sa,watchTypegen:()=>xa,writeTypegenArtifacts:()=>ba});function va(e){let t=e.cwd??process.cwd();return{cwd:t,srcDir:v(t,e.srcDir??`src`),outDir:v(t,e.outDir??`.kickjs/types`),silent:e.silent??!1,allowDuplicates:e.allowDuplicates??!1,schemaValidator:e.schemaValidator??!1,envFile:e.envFile??`src/env.ts`}}async function q(e={}){let{cwd:t,srcDir:n,outDir:r,silent:i,allowDuplicates:a,envFile:o}=va(e),s=Date.now(),c=await Ji({root:n,cwd:t,envFile:o===!1?void 0:o});if(c.collisions.length>0&&!a)throw new Xi(c.collisions);let l=da(e.assetMap,t),u=[],d=[];if(e.runPlugins!==!1){try{let{runAllPluginTypegens:e}=await Promise.resolve().then(()=>Pa),{loadKickConfig:n}=await Promise.resolve().then(()=>Me);u=await e({cwd:t,config:await n(t),silent:!0})}catch(e){if(!i){let t=e instanceof Error?e.message:String(e);console.warn(` kick typegen: plugin pipeline failed (${t}) — continuing`)}}d.push(...await ba(r,u,i))}let f=la(c.tokens),p=ya(c,l.count,d),m=Date.now()-s;if(!i){let e=r.replace(t+`/`,``),n=p.resolvedCollisions>0?`, ${p.resolvedCollisions} collisions namespaced`:``,i=p.envWritten?`, env typed`:``,a=p.pluginEntries>0?`, ${p.pluginEntries} plugins/adapters`:``,o=p.augmentationEntries>0?`, ${p.augmentationEntries} augmentations`:``,s=p.assetEntries>0?`, ${p.assetEntries} assets`:``;if(console.log(` kick typegen → ${p.serviceTokens} services, ${p.routeEntries} routes, ${p.moduleTokens} modules${a}${o}${s}${i}${n} → ${e} (${m}ms)`),f.length>0){console.warn(` kick typegen: ${f.length} token(s) don't match the §22.2 convention:`);for(let e of f){let t=e.variable?` [${e.variable}]`:``;console.warn(` '${e.token}' (${e.filePath})${t} — ${e.reason}`),e.suggestion&&console.warn(` → suggestion: ${e.suggestion}`)}}if(c.orphanedClasses.length>0){console.warn(` kick typegen: ${c.orphanedClasses.length} decorated class(es) not matched by any module's import.meta.glob():`);for(let e of c.orphanedClasses)console.warn(` @${e.decorator} ${e.className} (${e.relativePath})`),console.warn(` → not picked up by any glob in ${e.moduleFilePath}`)}}return{scan:c,result:p,tokenWarnings:f}}function ya(e,t,n){let r=new Set(e.collisions.map(e=>e.className)),i=e.classes.filter(e=>Yi.has(e.decorator)),a=ia(e.classes,e.tokens,e.injects,r);return{registryEntries:i.length,serviceTokens:new Set(a).size,moduleTokens:aa(e.classes).length,routeEntries:e.routes.length,pluginEntries:new Set(e.pluginsAndAdapters.map(e=>e.name)).size,augmentationEntries:new Set(e.augmentations.map(e=>e.name)).size,assetEntries:t,envWritten:e.env!==null,written:n,resolvedCollisions:e.collisions.length}}async function ba(e,t,n){await oe(e,{recursive:!0}),await w(h(f(e),`.gitignore`),`# Auto-generated by kick typegen
2445
+ `}const zi=Symbol(`asset-leaf`);function Bi(e,t){let n=Object.keys(e).toSorted(),r=[];for(let i of n){let n=e[i],a=Vi(i)?i:JSON.stringify(i);n===zi?r.push(`${t}${a}: () => string`):(r.push(`${t}${a}: {`),r.push(Bi(n,`${t} `)),r.push(`${t}}`))}return r.join(`
2446
+ `)}function Vi(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)}function Hi(e){try{return c(e).isDirectory()}catch{return!1}}var Ui=A({runTypegen:()=>J,sweepStaleTypegen:()=>Ji,watchTypegen:()=>qi,writeTypegenArtifacts:()=>Ki});function Wi(e){let t=e.cwd??process.cwd();return{cwd:t,srcDir:v(t,e.srcDir??`src`),outDir:v(t,e.outDir??`.kickjs/types`),silent:e.silent??!1,allowDuplicates:e.allowDuplicates??!1,schemaValidator:e.schemaValidator??!1,envFile:e.envFile??`src/env.ts`}}async function J(e={}){let{cwd:t,srcDir:n,outDir:r,silent:i,allowDuplicates:a,envFile:o}=Wi(e),s=Date.now(),c={root:n,cwd:t,cacheDir:v(t,`.kickjs`,`cache`),envFile:o===!1?void 0:o},l=e.changedFiles?await yi(c,e.changedFiles):await _i(c);if(l.collisions.length>0&&!a)throw new Si(l.collisions);let u=Li(e.assetMap,t),d=[],f=[];if(e.runPlugins!==!1){try{let{runAllPluginTypegens:n}=await Promise.resolve().then(()=>sa),{loadKickConfig:r}=await Promise.resolve().then(()=>Se);d=await n({cwd:t,config:await r(t),silent:!0,changedFiles:e.changedFiles})}catch(e){if(!i){let t=e instanceof Error?e.message:String(e);console.warn(` kick typegen: plugin pipeline failed (${t}) — continuing`)}}f.push(...await Ki(r,d,i))}let p=Fi(l.tokens),m=Gi(l,u.count,f),h=Date.now()-s;if(!i){let e=r.replace(t+`/`,``),n=m.resolvedCollisions>0?`, ${m.resolvedCollisions} collisions namespaced`:``,i=m.envWritten?`, env typed`:``,a=m.pluginEntries>0?`, ${m.pluginEntries} plugins/adapters`:``,o=m.augmentationEntries>0?`, ${m.augmentationEntries} augmentations`:``,s=m.assetEntries>0?`, ${m.assetEntries} assets`:``;if(console.log(` kick typegen → ${m.serviceTokens} services, ${m.routeEntries} routes, ${m.moduleTokens} modules${a}${o}${s}${i}${n} → ${e} (${h}ms)`),p.length>0){console.warn(` kick typegen: ${p.length} token(s) don't match the §22.2 convention:`);for(let e of p){let t=e.variable?` [${e.variable}]`:``;console.warn(` '${e.token}' (${e.filePath})${t} — ${e.reason}`),e.suggestion&&console.warn(` → suggestion: ${e.suggestion}`)}}if(l.orphanedClasses.length>0){console.warn(` kick typegen: ${l.orphanedClasses.length} decorated class(es) not matched by any module's import.meta.glob():`);for(let e of l.orphanedClasses)console.warn(` @${e.decorator} ${e.className} (${e.relativePath})`),console.warn(` → not picked up by any glob in ${e.moduleFilePath}`)}}return{scan:l,result:m,tokenWarnings:p}}function Gi(e,t,n){let r=new Set(e.collisions.map(e=>e.className)),i=e.classes.filter(e=>xi.has(e.decorator)),a=Ai(e.classes,e.tokens,e.injects,r);return{registryEntries:i.length,serviceTokens:new Set(a).size,moduleTokens:ji(e.classes).length,routeEntries:e.routes.length,pluginEntries:new Set(e.pluginsAndAdapters.map(e=>e.name)).size,augmentationEntries:new Set(e.augmentations.map(e=>e.name)).size,assetEntries:t,envWritten:e.env!==null,written:n,resolvedCollisions:e.collisions.length}}async function Ki(e,t,n){await w(e,{recursive:!0}),await E(h(f(e),`.gitignore`),`# Auto-generated by kick typegen
3671
2447
  *
3672
- `,`utf-8`);let r=t.filter(e=>e.outFile).map(e=>e.outFile);return await Sa(e,r,t,n),r}async function xa(e={}){let t=va(e),{srcDir:n,silent:r,cwd:i}=t,a={...t,allowDuplicates:!0,runPlugins:!1},o=process.env.KICKJS_WATCH_POLLING===`1`||process.env.KICKJS_WATCH_POLLING===`true`,[{runAllPluginTypegens:s},{loadKickConfig:c}]=await Promise.all([Promise.resolve().then(()=>Pa),Promise.resolve().then(()=>Me)]),l=await c(i),u=async()=>{try{await q({...a})}catch(e){if(r)return;if(e instanceof Xi)console.error(`
2448
+ `,`utf-8`);let r=t.filter(e=>e.outFile).map(e=>e.outFile);return await Ji(e,r,t,n),r}async function qi(e={}){let t=Wi(e),{srcDir:n,silent:r,cwd:i}=t,a={...t,allowDuplicates:!0,runPlugins:!1},o=process.env.KICKJS_WATCH_POLLING===`1`||process.env.KICKJS_WATCH_POLLING===`true`,[{runAllPluginTypegens:s},{loadKickConfig:c}]=await Promise.all([Promise.resolve().then(()=>sa),Promise.resolve().then(()=>Se)]),l=await c(i),u=async()=>{try{await J({...a})}catch(e){if(r)return;if(e instanceof Si)console.error(`
3673
2449
  `+e.message+`
3674
- `);else{let t=e instanceof Error?e.message:String(e);console.error(` kick typegen failed: ${t}`)}}},d=async()=>{try{let e=await s({cwd:i,config:l,silent:!0});await ba(t.outDir,e,!0)}catch{}};await u(),await d();let{watch:f}=await import(`node:fs`),p=null,m=e=>{e&&/\.(ts|tsx|mts|cts)$/.test(e)&&(e.includes(`.kickjs`)||e.endsWith(`.d.ts`)||(p&&clearTimeout(p),p=setTimeout(()=>{u().then(d)},100)))};if(o){r||console.log(` kick typegen: polling mode (KICKJS_WATCH_POLLING)`);let e=setInterval(()=>{u().then(d)},2e3);return()=>clearInterval(e)}let h;try{h=f(n,{recursive:!0},(e,t)=>{m(t)})}catch(e){r||console.warn(` kick typegen: watch mode unavailable (${e?.message??e}). Falling back to polling.`);let t=setInterval(()=>{u().then(d)},2e3);return()=>clearInterval(t)}return()=>{p&&clearTimeout(p),h.close()}}async function Sa(e,t,n,r){let i=new Set;for(let e of t)i.add(d(e));for(let e of n)e.outFile&&i.add(d(e.outFile));let a;try{a=await se(e)}catch{return[]}let o=[];for(let t of a){if(!Ca.has(t)||i.has(t))continue;let n=v(e,t);try{if(!(await le(n)).isFile())continue;await ue(n),o.push(t)}catch{}}return o.length>0&&!r&&console.log(` kick typegen: swept ${o.length} stale file(s): ${o.join(`, `)}`),o}const Ca=new Set([`assets.d.ts`,`env.ts`,`routes.ts`,`registry.d.ts`,`services.d.ts`,`modules.d.ts`,`plugins.d.ts`,`augmentations.d.ts`,`index.d.ts`]),wa=[`agents`,`claude`,`skills`,`gemini`,`copilot`,`both`,`all`];function J(e){return e.parent?.opts()?.dryRun??!1}function Y(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(`
3675
- (dry run — no files were written)`),console.log()}async function Ta(e){if(!e)try{let e=await k(process.cwd());await q({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 Ea=[{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:`contributor <name>`,description:`Context contributor [--type http|bare] [--params a:string] [-m]`},{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 Da(){console.log(`
2450
+ `);else{let t=e instanceof Error?e.message:String(e);console.error(` kick typegen failed: ${t}`)}}},d=async()=>{try{let e=await s({cwd:i,config:l,silent:!0});await Ki(t.outDir,e,!0)}catch{}};await u(),await d();let{watch:f}=await import(`node:fs`),p=null,m=e=>{e&&/\.(ts|tsx|mts|cts)$/.test(e)&&(e.includes(`.kickjs`)||e.endsWith(`.d.ts`)||(p&&clearTimeout(p),p=setTimeout(()=>{u().then(d)},100)))};if(o){r||console.log(` kick typegen: polling mode (KICKJS_WATCH_POLLING)`);let e=setInterval(()=>{u().then(d)},2e3);return()=>clearInterval(e)}let h;try{h=f(n,{recursive:!0},(e,t)=>{m(t)})}catch(e){r||console.warn(` kick typegen: watch mode unavailable (${e?.message??e}). Falling back to polling.`);let t=setInterval(()=>{u().then(d)},2e3);return()=>clearInterval(t)}return()=>{p&&clearTimeout(p),h.close()}}async function Ji(e,t,n,r){let i=new Set;for(let e of t)i.add(d(e));for(let e of n)e.outFile&&i.add(d(e.outFile));let a;try{a=await ae(e)}catch{return[]}let o=[];for(let t of a){if(!Yi.has(t)||i.has(t))continue;let n=v(e,t);try{if(!(await se(n)).isFile())continue;await ce(n),o.push(t)}catch{}}return o.length>0&&!r&&console.log(` kick typegen: swept ${o.length} stale file(s): ${o.join(`, `)}`),o}const Yi=new Set([`assets.d.ts`,`env.ts`,`routes.ts`,`registry.d.ts`,`services.d.ts`,`modules.d.ts`,`plugins.d.ts`,`augmentations.d.ts`,`index.d.ts`]),Xi=[`agents`,`claude`,`skills`,`gemini`,`copilot`,`both`,`all`];function Y(e){return e.parent?.opts()?.dryRun??!1}function X(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(`
2451
+ (dry run — no files were written)`),console.log()}async function Zi(e){if(!e)try{let e=await M(process.cwd());await J({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 Qi=[{name:`module <name>`,description:`REST module (controller, service, DTOs, 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:`contributor <name>`,description:`Context contributor [--type http|bare] [--params a:string] [-m]`},{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`}],$i=new Set(Qi.map(e=>e.name.split(` `)[0]));async function ea(){console.log(`
3676
2452
  Built-in generators:
3677
- `);let e=Math.max(...Ea.map(e=>e.name.length));for(let t of Ea)console.log(` kick g ${t.name.padEnd(e+2)} ${t.description}`);let t=await k(process.cwd()),n=Ue(t?.plugins??[],t?.commands??[]),r=await fn(process.cwd(),n.generators);if(r.generators.length>0){console.log(`
2453
+ `);let e=Math.max(...Qi.map(e=>e.name.length));for(let t of Qi)console.log(` kick g ${t.name.padEnd(e+2)} ${t.description}`);let t=await M(process.cwd()),n=Pe(t?.plugins??[],t?.commands??[]),r=await nn(process.cwd(),n.generators);if(r.generators.length>0){console.log(`
3678
2454
  Plugin generators:
3679
2455
  `);let e=Math.max(...r.generators.map(e=>`${e.spec.name} <name>`.length));for(let{source:t,spec:n}of r.generators){let r=`${n.name} <name>`;console.log(` kick g ${r.padEnd(e+2)} ${n.description} [${t}]`)}}if(r.failed.length>0){console.log(`
3680
2456
  Failed to load:
3681
- `);for(let{source:e,reason:t}of r.failed)console.log(` ${e} — ${t}`)}console.log()}async function Oa(e,t,n){let r=await k(process.cwd()),i=O(r),a=t.modulesDir??i.dir??`src/modules`,o=t.repo??Qn(i.repo),s=t.pattern??r?.pattern??`ddd`,c=t.pluralize===!1?!1:i.pluralize??!0,l=Ie(r,process.cwd()),u=i.style??`define`;if(!n&&u===`define`){let e=await zr(v(a),`define`);if(e.length>0){console.error(`\n ${E.red(`Error:`)} ${e.length} module file(s) still use the legacy \`class … implements AppModule\` shape.\n ${E.dim(`Project setting:`)} modules.style: 'define' (default)\n\n ${E.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 ${E.bold(`Pick one:`)}\n 1. Migrate everything to defineModule:\n ${E.dim(`$`)} kick codemod modules --experimental --apply\n 2. Keep the class form — pin it in kick.config.ts:\n ${E.dim(`// kick.config.ts`)}\n ${E.dim(`export default defineConfig({ modules: { style: 'class' } })`)}\n`),process.exit(1)}}let d=[];for(let r of e){let e=await $n({name:r,modulesDir:v(a),noEntity:t.entity===!1,noTests:t.tests===!1,repo:o,minimal:t.minimal,force:t.force,pattern:s,dryRun:n,pluralize:c,prismaClientPath:i.prismaClientPath,tokenScope:l,style:i.style});d.push(...e)}Y(d,n),await Ta(n)}function ka(e,t){let n=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,r,i)=>{if(r.list){await Da();return}if(!e||e.length===0){n.help();return}let a=J(i);j(a);let[o,s,...c]=e;if(o){let e=await k(process.cwd()),n=Ue(e?.plugins??[],e?.commands??[]),i=await dn({generatorName:o,itemName:s??``,args:c,flags:r,cwd:process.cwd(),projectRoot:t?.projectRoot},n.generators);if(i){Y(i.files,a);return}}await Oa(e,r,a)});n.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=J(n);j(r),await Oa(e,{...n.optsWithGlobals(),...t},r)}),n.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=J(n);j(r),Y(await sr({name:e,outDir:v(t.out)}),r)}),n.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=J(n);j(r),Y(await cr({name:e,outDir:v(t.out)}),r)}),n.command(`middleware <name>`).description(`Generate an Express middleware function
3682
- 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,n)=>{let r=J(n);j(r);let i=await k(process.cwd()),a=O(i),o=a.dir??`src/modules`;Y(await fr({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r)}),n.command(`guard <name>`).description(`Generate a route guard (auth, roles, etc.)
3683
- 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,n)=>{let r=J(n);j(r);let i=await k(process.cwd()),a=O(i),o=a.dir??`src/modules`;Y(await pr({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r)}),n.command(`contributor <name>`).description(`Generate a Context Contributor (typed alternative to @Middleware for ctx.set)
2457
+ `);for(let{source:e,reason:t}of r.failed)console.log(` ${e} — ${t}`)}console.log()}async function ta(e,t,n){let r=await M(process.cwd()),i=j(r),a=t.modulesDir??i.dir??`src/modules`,o=t.repo??Tn(i.repo);t.repo&&Ee(t.repo);let s=t.pattern??r?.pattern??`rest`,c=t.pluralize===!1?!1:i.pluralize??!0,l=Oe(r,process.cwd()),u=i.style??`define`;if(!n&&u===`define`){let e=await ur(v(a),`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 d=[];for(let r of e){let e=await En({name:r,modulesDir:v(a),noEntity:t.entity===!1,noTests:t.tests===!1,repo:o,minimal:t.minimal,force:t.force,pattern:s,dryRun:n,pluralize:c,prismaClientPath:i.prismaClientPath,tokenScope:l,style:i.style});d.push(...e)}X(d,n),await Zi(n)}function na(e,t){let n=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 name: inmemory (default) or any DB name (e.g. postgres)`).option(`--pattern <pattern>`,`Override project pattern: rest | 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,r,i)=>{if(r.list){await ea();return}if(!e||e.length===0){n.help();return}let a=Y(i);N(a);let[o,s,...c]=e;if(o){let e=await M(process.cwd()),n=Pe(e?.plugins??[],e?.commands??[]),i=await tn({generatorName:o,itemName:s??``,args:c,flags:r,cwd:process.cwd(),projectRoot:t?.projectRoot},n.generators);if(i){X(i.files,a);return}if(o!==`module`&&$i.has(o)){console.error(`\n '${o}' is a generator, not a module name.`),console.error(` Did you mean: kick g ${o} ${s??`<name>`}`),console.error(` If that errors, your @forinda/kickjs-cli is older than the '${o}' generator — upgrade it.\n`),process.exitCode=1;return}}await ta(e,r,a)});n.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 name: inmemory (default) or any DB name (e.g. postgres)`).option(`--pattern <pattern>`,`Override project pattern: rest | 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=Y(n);N(r),await ta(e,{...n.optsWithGlobals(),...t},r)}),n.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=Y(n);N(r),X(await Pn({name:e,outDir:v(t.out)}),r)}),n.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=Y(n);N(r),X(await Fn({name:e,outDir:v(t.out)}),r)}),n.command(`middleware <name>`).description(`Generate an Express middleware function
2458
+ 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,n)=>{let r=Y(n);N(r);let i=await M(process.cwd()),a=j(i),o=a.dir??`src/modules`;X(await Ln({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r)}),n.command(`guard <name>`).description(`Generate a route guard (auth, roles, etc.)
2459
+ 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,n)=>{let r=Y(n);N(r);let i=await M(process.cwd()),a=j(i),o=a.dir??`src/modules`;X(await Rn({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r)}),n.command(`contributor <name>`).description(`Generate a Context Contributor (typed alternative to @Middleware for ctx.set)
3684
2460
  --type http (default, RequestContext) | bare (ExecutionContext)
3685
2461
  --params "source:string,region:number" → emits the withParams<T>() form
3686
- Use -m to scope it to a module: kick g contributor tenant -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).option(`-t, --type <type>`,`Contributor flavour: http | bare`,`http`).option(`-k, --key <key>`,`Context key it writes (defaults to camelCase of name)`).option(`--params <fields>`,`Per-call params, e.g. "source:string,region:number"`).action(async(e,t,n)=>{let r=J(n);j(r);let i=(t.type??`http`).toLowerCase();i!==`http`&&i!==`bare`&&(console.warn(` kick g contributor: unknown --type '${t.type}', using 'http'.`),i=`http`);let a=await k(process.cwd()),o=O(a),s=o.dir??`src/modules`;Y(await gr({name:e,type:i,key:t.key,params:t.params,outDir:t.out,moduleName:t.module,modulesDir:s,pattern:a?.pattern,pluralize:o.pluralize??!0}),r)}),n.command(`service <name>`).description(`Generate a @Service() class
3687
- 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,n)=>{let r=J(n);j(r);let i=await k(process.cwd()),a=O(i),o=a.dir??`src/modules`;Y(await _r({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r)}),n.command(`controller <name>`).description(`Generate a @Controller() class with basic routes
3688
- 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,n)=>{let r=J(n);j(r);let i=await k(process.cwd()),a=O(i),o=a.dir??`src/modules`;Y(await vr({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r),await Ta(r)}),n.command(`dto <name>`).description(`Generate a Zod DTO schema
3689
- 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,n)=>{let r=J(n);j(r);let i=await k(process.cwd()),a=O(i),o=a.dir??`src/modules`;Y(await yr({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r)}),n.command(`test <name>`).description(`Generate a Vitest test scaffold
3690
- 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,n)=>{let r=J(n);j(r);let i=O(await k(process.cwd())),a=i.dir??`src/modules`;Y(await ni({name:e,outDir:t.out,moduleName:t.module,modulesDir:a,pluralize:i.pluralize??!0}),r)}),n.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=J(n);j(r),Y(await Br({name:e,outDir:v(t.out),queue:t.queue}),r)}),n.command(`scaffold <name> [fields...]`).description(`Generate a full CRUD module from field definitions
2462
+ Use -m to scope it to a module: kick g contributor tenant -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).option(`-t, --type <type>`,`Contributor flavour: http | bare`,`http`).option(`-k, --key <key>`,`Context key it writes (defaults to camelCase of name)`).option(`--params <fields>`,`Per-call params, e.g. "source:string,region:number"`).action(async(e,t,n)=>{let r=Y(n);N(r);let i=(t.type??`http`).toLowerCase();i!==`http`&&i!==`bare`&&(console.warn(` kick g contributor: unknown --type '${t.type}', using 'http'.`),i=`http`);let a=await M(process.cwd()),o=j(a),s=o.dir??`src/modules`;X(await Vn({name:e,type:i,key:t.key,params:t.params,outDir:t.out,moduleName:t.module,modulesDir:s,pattern:a?.pattern,pluralize:o.pluralize??!0}),r)}),n.command(`service <name>`).description(`Generate a @Service() class
2463
+ 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,n)=>{let r=Y(n);N(r);let i=await M(process.cwd()),a=j(i),o=a.dir??`src/modules`;X(await Hn({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r)}),n.command(`controller <name>`).description(`Generate a @Controller() class with basic routes
2464
+ 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,n)=>{let r=Y(n);N(r);let i=await M(process.cwd()),a=j(i),o=a.dir??`src/modules`;X(await Un({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r),await Zi(r)}),n.command(`dto <name>`).description(`Generate a Zod DTO schema
2465
+ 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,n)=>{let r=Y(n);N(r);let i=await M(process.cwd()),a=j(i),o=a.dir??`src/modules`;X(await Wn({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r)}),n.command(`test <name>`).description(`Generate a Vitest test scaffold
2466
+ 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,n)=>{let r=Y(n);N(r);let i=j(await M(process.cwd())),a=i.dir??`src/modules`;X(await vr({name:e,outDir:t.out,moduleName:t.module,modulesDir:a,pluralize:i.pluralize??!0}),r)}),n.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=Y(n);N(r),X(await dr({name:e,outDir:v(t.out),queue:t.queue}),r)}),n.command(`scaffold <name> [fields...]`).description(`Generate a full CRUD module from field definitions
3691
2467
  Example: kick g scaffold Post title:string body:text:optional published:boolean:optional
3692
2468
  Types: string, text, number, int, float, boolean, date, email, url, uuid, json, enum:a,b,c
3693
2469
  Optional: append :optional (shell-safe): description:text:optional
3694
- 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,t,n,r)=>{let i=J(r);j(i),t.length===0&&(console.error(`
2470
+ 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,t,n,r)=>{let i=Y(r);N(i),t.length===0&&(console.error(`
3695
2471
  Error: At least one field is required.
3696
2472
  Usage: kick g scaffold <name> <field:type> [field:type...]
3697
2473
  Example: kick g scaffold Post title:string body:text:optional published:boolean:optional
3698
2474
  Optional: append :optional (shell-safe, no quoting needed)
3699
- `),process.exit(1));let a=await k(process.cwd()),o=O(a),s=n.modulesDir??o.dir??`src/modules`,c=Hr(t),l=Ie(a,process.cwd()),u=a?.pattern??`ddd`;u!==`ddd`&&(console.error(`\n Error: 'kick g scaffold' currently only supports the DDD pattern.\n Detected project pattern: '${u}'.\n Workarounds:\n - Run 'kick g module ${e}' for the ${u} 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 d=await Ur({name:e,fields:c,modulesDir:v(s),noEntity:n.entity===!1,noTests:n.tests===!1,pluralize:n.pluralize===!1?!1:o.pluralize??!0,tokenScope:l,style:o.style});console.log(`\n Scaffolded ${e} with ${c.length} field(s):`);for(let e of c)console.log(` ${e.name}: ${e.type}${e.optional?` (optional)`:``}`);Y(d,i),await Ta(i)}),n.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=J(t);j(n),Y(await br({outDir:v(`.`),modulesDir:e.modulesDir,defaultRepo:e.repo,force:e.force}),n)}),n.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=J(t);j(n);let r=e.only??`all`;if(!wa.includes(r)){console.error(` Invalid --only value: ${r}. Expected: ${wa.join(` | `)}`),process.exitCode=1;return}Y(await Dr({outDir:v(`.`),only:r,name:e.name,pm:e.pm,template:e.template,force:e.force}),n)});for(let e of t?.generators??[])Aa(n,e,t?.projectRoot)}function Aa(e,t,n){let{source:r,spec:i}=t,a=i.args?.[0],o=a?.name??`itemName`,s=a?.required?`<${o}>`:`[${o}]`,c=`${i.name} ${s} [extraArgs...]`,l=e.command(c).description(`${i.description} [${r}]`);for(let e of i.flags??[]){let t=e.takesValue?`--${e.name} <value>`:`--${e.name}`,n=e.alias?`-${e.alias}, ${t}`:t;l.option(n,e.description??``)}l.action(async(e,r,a,o)=>{let s=J(o);j(s);let c=await dn({generatorName:i.name,itemName:e??``,args:r??[],flags:a,cwd:process.cwd(),projectRoot:n},[t]);c&&Y(c.files,s)})}async function ja(e){let t=u.resolve(e.cwd,`.kickjs/types`);await oe(t,{recursive:!0});let n=new Map,i=e.scan??Ji,a={cwd:e.cwd,config:e.config,async importTs(e){return await import(x(e).href)},async writeFile(t,n){let r=u.resolve(e.cwd,t);await oe(u.dirname(r),{recursive:!0}),await w(r,n,`utf8`)},getScanResult:e=>{let t=Ma(e),r=n.get(t);return r||(r=i(e),n.set(t,r)),r},log:console},o=[];for(let n of e.plugins){let i=n.outExtension??`.d.ts`,s=u.join(t,`${n.id.replace(/\//g,`__`)}${i}`),c;try{c=await n.generate(a)}catch(e){let t=e instanceof Error?e.message:String(e);a.log.error(` ${n.id}: typegen failed (${t}) — keeping previous output`),o.push({id:n.id,status:`error`,outFile:s});continue}if(c===null){o.push({id:n.id,status:`skipped`});continue}let l=`/* AUTO-GENERATED by kick typegen — do not edit. Plugin: ${n.id} */\n\n`+c+`
3700
- `,d=``;if(r(s)&&(d=await C(s,`utf8`)),d===l){o.push({id:n.id,status:`unchanged`,outFile:s});continue}if(e.check)throw Error(`kick typegen --check: drift detected for ${n.id} (${s})`);await w(s,l,`utf8`),o.push({id:n.id,status:`written`,outFile:s})}return o}function Ma(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 Na(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 Pa=D({applyDisableFilter:()=>Na,runAllPluginTypegens:()=>Fa});async function Fa(e){let{enabled:t,skipped:n,unknown:r}=Na(Ue([...Xs,...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 ja({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 Ia(e,t){let{cwd:n,silent:r=!1}=t,a=t.distDir??e?.build?.outDir??`dist`,o=e?.assetMap;if(!o||Object.keys(o).length===0)return null;let s=r?()=>{}:console.log,c=v(n,a);i(c,{recursive:!0});let u=[],d={};for(let[e,t]of Object.entries(o)){let r=await La(e,t,n,c);u.push(r.entrySummary),Object.assign(d,r.manifestSlice),s(` ✓ ${e}: ${r.entrySummary.filesCopied} file(s) → ${r.entrySummary.dest}`)}let f={version:1,entries:d},p=h(c,`.kickjs-assets.json`);return l(p,JSON.stringify(f,null,2)+`
3701
- `,`utf-8`),s(` ✓ wrote manifest → ${_(n,p)} (${Object.keys(d).length} entries)`),{manifestPath:p,entries:u,manifest:f}}async function La(e,t,a,o){let s=v(a,t.src),c=t.dest?v(a,t.dest):h(o,e);if(za(c,a))return console.warn(` ⚠ assetMap.${e}.dest ('${t.dest}') resolves outside the project root — skipping copy`),{entrySummary:{namespace:e,src:t.src,dest:_(a,c),filesCopied:0},manifestSlice:{}};if(!r(s)||!Ba(s))return{entrySummary:{namespace:e,src:t.src,dest:_(a,c),filesCopied:0},manifestSlice:{}};let l=await fe(t.glob??`**/*`,{cwd:s,nodir:!0,dot:!1,posix:!0});i(c,{recursive:!0});let u={},{pairs:d,collisionGroupsResolved:p}=me(e,[...l].toSorted(),{strategy:t.keys??`auto`});for(let{rel:e,key:t}of d){let r=h(s,e),a=h(c,e);i(f(a),{recursive:!0}),n(r,a),u[t]=Ra(o,a)}return p>0&&console.log(` ℹ assetMap.${e}: auto-resolved ${p} 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:_(a,c),filesCopied:l.length},manifestSlice:u}}function Ra(e,t){return _(e,t).split(/[\\/]/).filter(Boolean).join(`/`)}function za(e,t){let n=_(t,e);return n===``?!1:n.startsWith(`..`)||m(n)}function Ba(e){try{return c(e).isDirectory()}catch{return!1}}function Va(e){if(typeof e==`boolean`)return e;let t=process.env.KICKJS_WATCH_POLLING;return t===`1`||t===`true`}async function Ha(e,t,n={}){t&&(process.env.PORT=t);let r=Va(n.polling),i=process.cwd(),a=await k(i),o=a?.typegen?.schemaValidator??`zod`,s=a?.typegen?.envFile;try{await q({cwd:i,allowDuplicates:!0,schemaValidator:o,envFile:s,srcDir:a?.typegen?.srcDir,outDir:a?.typegen?.outDir,assetMap:a?.assetMap,runPlugins:!1})}catch(e){console.warn(` kick typegen: skipped (${e?.message??e})`)}let c=v(i,a?.typegen?.outDir??`.kickjs/types`);try{await ba(c,await Fa({cwd:i,config:a}),!1)}catch(e){console.warn(` kick typegen: plugin pass skipped (${e?.message??e})`)}let{createRequire:l}=await import(`node:module`),{createServer:u}=await import(x(l(v(`package.json`)).resolve(`vite`)).href),d=await u({configFile:v(`vite.config.ts`),server:{port:t?parseInt(t,10):void 0,...r?{watch:{usePolling:!0,interval:100}}:{}}}),f=a?.assetMap?Object.values(a.assetMap).map(e=>e?.src).filter(e=>typeof e==`string`&&e.length>0).map(e=>v(i,e)):[],p=e=>f.some(t=>e===t||e.startsWith(`${t}/`)),m=null,h=e=>{if(e.includes(`.kickjs`)||e.endsWith(`.d.ts`))return;let t=/\.(ts|tsx|mts|cts)$/.test(e),n=p(e);!t&&!n||(m&&clearTimeout(m),m=setTimeout(()=>{q({cwd:i,silent:!0,allowDuplicates:!0,schemaValidator:o,envFile:s,srcDir:a?.typegen?.srcDir,outDir:a?.typegen?.outDir,assetMap:a?.assetMap,runPlugins:!1}).catch(()=>{}),Fa({cwd:i,config:a,silent:!0}).then(e=>ba(c,e,!0)).catch(()=>{})},100))};d.watcher.on(`add`,h),d.watcher.on(`unlink`,h),d.watcher.on(`change`,h),f.length>0&&d.watcher.add(f),await d.listen(),d.printUrls(),console.log(`
2475
+ `),process.exit(1));let a=await M(process.cwd()),o=j(a),s=n.modulesDir??o.dir??`src/modules`,c=pr(t),l=Oe(a,process.cwd()),u=await mr({name:e,fields:c,modulesDir:v(s),noEntity:n.entity===!1,noTests:n.tests===!1,pluralize:n.pluralize===!1?!1:o.pluralize??!0,tokenScope:l,style:o.style});console.log(`\n Scaffolded ${e} with ${c.length} field(s):`);for(let e of c)console.log(` ${e.name}: ${e.type}${e.optional?` (optional)`:``}`);X(u,i),await Zi(i)}),n.command(`config`).description(`Generate a kick.config.ts at the project root`).option(`--modules-dir <dir>`,`Modules directory path`,`src/modules`).option(`--repo <type>`,`Repository name: inmemory (default) or any DB name`,`inmemory`).option(`-f, --force`,`Overwrite existing kick.config.ts without prompting`).action(async(e,t)=>{let n=Y(t);N(n),X(await Gn({outDir:v(`.`),modulesDir:e.modulesDir,defaultRepo:e.repo,force:e.force}),n)}),n.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 | minimal`).option(`-f, --force`,`Overwrite existing files without prompting`).action(async(e,t)=>{let n=Y(t);N(n);let r=e.only??`all`;if(!Xi.includes(r)){console.error(` Invalid --only value: ${r}. Expected: ${Xi.join(` | `)}`),process.exitCode=1;return}X(await Qn({outDir:v(`.`),only:r,name:e.name,pm:e.pm,template:e.template,force:e.force}),n)});for(let e of t?.generators??[])ra(n,e,t?.projectRoot)}function ra(e,t,n){let{source:r,spec:i}=t,a=i.args?.[0],o=a?.name??`itemName`,s=a?.required?`<${o}>`:`[${o}]`,c=`${i.name} ${s} [extraArgs...]`,l=e.command(c).description(`${i.description} [${r}]`);for(let e of i.flags??[]){let t=e.takesValue?`--${e.name} <value>`:`--${e.name}`,n=e.alias?`-${e.alias}, ${t}`:t;l.option(n,e.description??``)}l.action(async(e,r,a,o)=>{let s=Y(o);N(s);let c=await tn({generatorName:i.name,itemName:e??``,args:r??[],flags:a,cwd:process.cwd(),projectRoot:n},[t]);c&&X(c.files,s)})}async function ia(e){let t=u.resolve(e.cwd,`.kickjs/types`);await w(t,{recursive:!0});let n=new Map,i=e.scan??_i,a=u.resolve(e.cwd,`.kickjs`,`cache`),o=e.scan?void 0:e.changedFiles,s={cwd:e.cwd,config:e.config,async importTs(e){return await import(x(e).href)},async writeFile(t,n){let r=u.resolve(e.cwd,t);await w(u.dirname(r),{recursive:!0}),await E(r,n,`utf8`)},getScanResult:e=>{let t=aa(e),r=n.get(t);if(!r){let s={cacheDir:a,...e};r=o?yi(s,o):i(s),n.set(t,r)}return r},log:console},c=[];for(let n of e.plugins){let i=n.outExtension??`.d.ts`,a=u.join(t,`${n.id.replace(/\//g,`__`)}${i}`),o;try{o=await n.generate(s)}catch(e){let t=e instanceof Error?e.message:String(e);s.log.error(` ${n.id}: typegen failed (${t}) — keeping previous output`),c.push({id:n.id,status:`error`,outFile:a});continue}if(o===null){c.push({id:n.id,status:`skipped`});continue}let l=`/* AUTO-GENERATED by kick typegen — do not edit. Plugin: ${n.id} */\n\n`+o+`
2476
+ `,d=``;if(r(a)&&(d=await T(a,`utf8`)),d===l){c.push({id:n.id,status:`unchanged`,outFile:a});continue}if(e.check)throw Error(`kick typegen --check: drift detected for ${n.id} (${a})`);await E(a,l,`utf8`),c.push({id:n.id,status:`written`,outFile:a})}return c}function aa(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 oa(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 sa=A({applyDisableFilter:()=>oa,runAllPluginTypegens:()=>la});function ca(){let e=(process.env.LOG_LEVEL??process.env.KICKJS_LOG_LEVEL??``).toLowerCase();return e===`debug`||e===`trace`}async function la(e){let{enabled:t,skipped:n,unknown:r}=oa(Pe([..._s,...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 ia({cwd:e.cwd,config:e.config??{},plugins:t,check:e.check,changedFiles:e.changedFiles});if(!e.silent&&ca())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 ua(e,t){let{cwd:n,silent:r=!1}=t,a=t.distDir??e?.build?.outDir??`dist`,o=e?.assetMap;if(!o||Object.keys(o).length===0)return null;let s=r?()=>{}:console.log,c=v(n,a);i(c,{recursive:!0});let u=[],d={};for(let[e,t]of Object.entries(o)){let r=await da(e,t,n,c);u.push(r.entrySummary),Object.assign(d,r.manifestSlice),s(` ✓ ${e}: ${r.entrySummary.filesCopied} file(s) → ${r.entrySummary.dest}`)}let f={version:1,entries:d},p=h(c,`.kickjs-assets.json`);return l(p,JSON.stringify(f,null,2)+`
2477
+ `,`utf-8`),s(` ✓ wrote manifest → ${_(n,p)} (${Object.keys(d).length} entries)`),{manifestPath:p,entries:u,manifest:f}}async function da(e,t,a,o){let s=v(a,t.src),c=t.dest?v(a,t.dest):h(o,e);if(ma(c,a))return console.warn(` ⚠ assetMap.${e}.dest ('${t.dest}') resolves outside the project root — skipping copy`),{entrySummary:{namespace:e,src:t.src,dest:_(a,c),filesCopied:0},manifestSlice:{}};if(!r(s)||!ha(s))return{entrySummary:{namespace:e,src:t.src,dest:_(a,c),filesCopied:0},manifestSlice:{}};let l=await de(t.glob??`**/*`,{cwd:s,nodir:!0,dot:!1,posix:!0});i(c,{recursive:!0});let u={},{pairs:d,collisionGroupsResolved:p}=pe(e,[...l].toSorted(),{strategy:t.keys??`auto`}),m=0;for(let{rel:e,key:t}of d){let r=h(s,e),a=h(c,e);u[t]=pa(o,a),!fa(r,a)&&(i(f(a),{recursive:!0}),n(r,a),m++)}return p>0&&console.log(` ℹ assetMap.${e}: auto-resolved ${p} 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:_(a,c),filesCopied:m},manifestSlice:u}}function fa(e,t){if(!r(t))return!1;try{let n=c(e),r=c(t);return r.size===n.size&&r.mtimeMs>=n.mtimeMs}catch{return!1}}function pa(e,t){return _(e,t).split(/[\\/]/).filter(Boolean).join(`/`)}function ma(e,t){let n=_(t,e);return n===``?!1:n.startsWith(`..`)||m(n)}function ha(e){try{return c(e).isDirectory()}catch{return!1}}function ga(e){if(typeof e==`boolean`)return e;let t=process.env.KICKJS_WATCH_POLLING;return t===`1`||t===`true`}async function _a(e,t,n={}){t&&(process.env.PORT=t);let r=ga(n.polling),i=process.cwd(),a=await M(i),o=a?.typegen?.schemaValidator??`zod`,s=a?.typegen?.envFile;try{await J({cwd:i,allowDuplicates:!0,schemaValidator:o,envFile:s,srcDir:a?.typegen?.srcDir,outDir:a?.typegen?.outDir,assetMap:a?.assetMap,runPlugins:!1})}catch(e){console.warn(` kick typegen: skipped (${e?.message??e})`)}let c=v(i,a?.typegen?.outDir??`.kickjs/types`);try{await Ki(c,await la({cwd:i,config:a}),!1)}catch(e){console.warn(` kick typegen: plugin pass skipped (${e?.message??e})`)}let{createRequire:l}=await import(`node:module`),{createServer:u}=await import(x(l(v(`package.json`)).resolve(`vite`)).href),d=await u({configFile:v(`vite.config.ts`),server:{port:t?parseInt(t,10):void 0,...r?{watch:{usePolling:!0,interval:100}}:{}}}),f=a?.assetMap?Object.values(a.assetMap).map(e=>e?.src).filter(e=>typeof e==`string`&&e.length>0).map(e=>v(i,e)):[],p=e=>f.some(t=>e===t||e.startsWith(`${t}/`)),m=null,h=new Set,g=new Set,_=!1,y=!1,b=!!a?.assetMap&&Object.keys(a.assetMap).length>0,S=(e,t)=>{if(!t.includes(`.kickjs`)){if(e===`unlinkDir`)_=!0,b&&(y=!0);else{if(t.endsWith(`.d.ts`))return;let n=/\.(ts|tsx|mts|cts)$/.test(t),r=p(t);if(!n&&!r)return;r&&b&&(y=!0),n&&(e===`unlink`?(g.add(t),h.delete(t)):(h.add(t),g.delete(t)))}m&&clearTimeout(m),m=setTimeout(()=>{let e=_?void 0:{changed:[...h],removed:[...g]},t=y;h.clear(),g.clear(),_=!1,y=!1,J({cwd:i,silent:!0,allowDuplicates:!0,schemaValidator:o,envFile:s,srcDir:a?.typegen?.srcDir,outDir:a?.typegen?.outDir,assetMap:a?.assetMap,changedFiles:e,runPlugins:!1}).catch(()=>{}),la({cwd:i,config:a,silent:!0,changedFiles:e}).then(e=>Ki(c,e,!0)).catch(()=>{}),t&&ua(a,{cwd:i,silent:!0}).catch(()=>{})},100)}};d.watcher.on(`add`,e=>S(`add`,e)),d.watcher.on(`unlink`,e=>S(`unlink`,e)),d.watcher.on(`change`,e=>S(`change`,e)),d.watcher.on(`unlinkDir`,e=>S(`unlinkDir`,e)),f.length>0&&d.watcher.add(f),await d.listen(),d.printUrls(),console.log(`
3702
2478
  KickJS dev server running (Vite + @forinda/kickjs-vite)
3703
- `);let g=!1,_=async()=>{if(!g){g=!0,m&&clearTimeout(m);try{await globalThis.__kickjs_app_shutdown?.()}catch(e){console.error(` app shutdown hook failed: ${e?.message??e}`)}await d.close(),process.exit(0)}};process.on(`SIGINT`,_),process.on(`SIGTERM`,_),process.on(`SIGBREAK`,_)}function Ua(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 Ha(e.entry,e.port,{polling:e.polling})}catch(e){e.code===`ERR_MODULE_NOT_FOUND`&&e.message?.includes(`vite`)?console.error(`
2479
+ `);let C=!1,ee=async()=>{if(!C){C=!0,m&&clearTimeout(m);try{await globalThis.__kickjs_app_shutdown?.()}catch(e){console.error(` app shutdown hook failed: ${e?.message??e}`)}await d.close(),process.exit(0)}};process.on(`SIGINT`,ee),process.on(`SIGTERM`,ee),process.on(`SIGBREAK`,ee)}function va(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 _a(e.entry,e.port,{polling:e.polling})}catch(e){e.code===`ERR_MODULE_NOT_FOUND`&&e.message?.includes(`vite`)?console.error(`
3704
2480
  Error: vite is not installed.
3705
2481
  Run: pnpm add -D vite unplugin-swc
3706
2482
  `):console.error(`
3707
2483
  Dev server failed:`,e.message??e),process.exit(1)}}),e.command(`build`).description(`Build for production via Vite`).action(async()=>{console.log(`
3708
2484
  Building for production...
3709
- `);let{createRequire:e}=await import(`node:module`),{build:t}=await import(x(e(v(`package.json`)).resolve(`vite`)).href);await t({configFile:v(`vite.config.ts`)});let a=await k(process.cwd()),o=a?.copyDirs??[];if(o.length>0){console.log(`
2485
+ `);let{createRequire:e}=await import(`node:module`),{build:t}=await import(x(e(v(`package.json`)).resolve(`vite`)).href);await t({configFile:v(`vite.config.ts`)});let a=await M(process.cwd()),o=a?.copyDirs??[];if(o.length>0){console.log(`
3710
2486
  Copying directories to dist...`);for(let e of o){let t=typeof e==`string`?e:e.src,a=typeof e==`string`?h(`dist`,e):e.dest??h(`dist`,t),o=v(t),s=v(a);if(!r(o)){console.log(` ⚠ Skipped ${t} (not found)`);continue}i(s,{recursive:!0}),n(o,s,{recursive:!0}),console.log(` ✓ ${t} → ${a}`)}}if(a?.assetMap&&Object.keys(a.assetMap).length>0){console.log(`
3711
- Building asset map...`);try{await Ia(a,{cwd:process.cwd()})}catch(e){console.error(` ✗ asset build failed: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}console.log(`
2487
+ Building asset map...`);try{await ua(a,{cwd:process.cwd()})}catch(e){console.error(` ✗ asset build failed: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}console.log(`
3712
2488
  Build complete.
3713
- `)}),e.command(`build:assets`).description(`Rebuild the .kickjs-assets.json manifest under the configured outDir (no JS rebuild)`).action(async()=>{let e=await k(process.cwd());if(!e?.assetMap||Object.keys(e.assetMap).length===0){console.log(` No assetMap entries — nothing to build.`);return}console.log(`
3714
- Building asset map...`);try{await Ia(e,{cwd:process.cwd()}),console.log(`
2489
+ `)}),e.command(`build:assets`).description(`Rebuild the .kickjs-assets.json manifest under the configured outDir (no JS rebuild)`).action(async()=>{let e=await M(process.cwd());if(!e?.assetMap||Object.keys(e.assetMap).length===0){console.log(` No assetMap entries — nothing to build.`);return}console.log(`
2490
+ Building asset map...`);try{await ua(e,{cwd:process.cwd()}),console.log(`
3715
2491
  Asset build complete.
3716
- `)}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)),ke(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 Ha(e.entry,e.port)}catch(e){console.error(`
3717
- Dev server (debug) failed:`,e.message??e),process.exit(1)}})}function Wa(e){e.command(`info`).description(`Print system and framework info`).action(()=>{console.log(`
2492
+ `)}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)),ye(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 _a(e.entry,e.port)}catch(e){console.error(`
2493
+ Dev server (debug) failed:`,e.message??e),process.exit(1)}})}function ya(e){e.command(`info`).description(`Print system and framework info`).action(()=>{console.log(`
3718
2494
  KickJS CLI
3719
2495
 
3720
2496
  System:
3721
- OS: ${ge()} ${_e()} (${he()})
2497
+ OS: ${he()} ${ge()} (${me()})
3722
2498
  Node: ${process.version}
3723
2499
 
3724
2500
  Packages:
3725
2501
  @forinda/kickjs workspace
3726
2502
  @forinda/kickjs-vite workspace
3727
2503
  @forinda/kickjs-cli workspace
3728
- `)})}const{bold:X,dim:Z,green:Ga,red:Ka,yellow:qa,blue:Ja}=E;function Ya(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 Xa(e){let t=await fetch(e,{signal:AbortSignal.timeout(5e3)});if(!t.ok)throw Error(`${t.status} ${t.statusText}`);return t.json()}async function Za(e,t){try{return await Xa(`${e}${t}`)}catch{return null}}async function Qa(e){let[t,n,r,i,a]=await Promise.all([Za(e,`/health`),Za(e,`/metrics`),Za(e,`/routes`),Za(e,`/container`),Za(e,`/ws`)]);return{health:t,metrics:n,routes:r,container:i,ws:a}}function $a(e,t){let{health:n,metrics:r,routes:i,container:a,ws:o}=t,s=Z(`─`.repeat(60));if(console.log(),console.log(X(` KickJS Inspector`)+Z(` → ${e}`)),console.log(s),n){let e=n.status===`healthy`?Ga(`● healthy`):Ka(`● `+n.status);console.log(` ${X(`Health:`)} ${e}`)}else console.log(` ${X(`Health:`)} ${Ka(`● unreachable`)}`);if(r){let e=((r.errorRate??0)*100).toFixed(1),t=r.errorRate>.1?Ka:r.errorRate>0?qa:Ga;console.log(` ${X(`Uptime:`)} ${Ya(r.uptimeSeconds)}`),console.log(` ${X(`Requests:`)} ${r.requests}`),console.log(` ${X(`Errors:`)} ${r.serverErrors} server, ${r.clientErrors??0} client ${Z(`(`)}${t(e+`%`)}${Z(`)`)}`)}if(a&&console.log(` ${X(`DI:`)} ${a.count} bindings`),o&&o.enabled&&console.log(` ${X(`WS:`)} ${o.connections??0} connections, ${o.namespaces??0} namespaces`),i?.routes?.length){console.log(),console.log(X(` Routes`)),console.log(s),console.log(` ${Z(`METHOD`)} ${Z(`PATH`.padEnd(36))} ${Z(`CONTROLLER`)}`);for(let e of i.routes){let t=e.path.length>36?e.path.slice(0,33)+`...`:e.path.padEnd(36);console.log(` ${Mt(e.method)} ${t} ${Ja(e.controller)}.${Z(e.handler)}`)}}console.log(s),console.log()}function eo(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 Qa(r);t.json?console.log(JSON.stringify(e,null,2)):$a(n,e)}catch(e){t.json?console.log(JSON.stringify({error:String(e)})):(console.error(Ka(` ✖ Could not connect to ${n}`)),console.error(Z(` ${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 to(e,t){let n=e.toLowerCase();return t.every(e=>n.includes(e.toLowerCase()))}function Q(e,t){let n=e.toLowerCase();return t.some(e=>n.includes(e.toLowerCase()))}const no=[{match(e,t){let n=to(e,[`config`,`get`])&&Q(e,[`undefined`,`null`]),r=e.includes(`@Value`)&&Q(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
2504
+ `)})}const{bold:Z,dim:Q,green:ba,red:xa,yellow:Sa,blue:Ca}=k;function wa(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 Ta(e){let t=await fetch(e,{signal:AbortSignal.timeout(5e3)});if(!t.ok)throw Error(`${t.status} ${t.statusText}`);return t.json()}async function Ea(e,t){try{return await Ta(`${e}${t}`)}catch{return null}}async function Da(e){let[t,n,r,i,a]=await Promise.all([Ea(e,`/health`),Ea(e,`/metrics`),Ea(e,`/routes`),Ea(e,`/container`),Ea(e,`/ws`)]);return{health:t,metrics:n,routes:r,container:i,ws:a}}function Oa(e,t){let{health:n,metrics:r,routes:i,container:a,ws:o}=t,s=Q(`─`.repeat(60));if(console.log(),console.log(Z(` KickJS Inspector`)+Q(` → ${e}`)),console.log(s),n){let e=n.status===`healthy`?ba(`● healthy`):xa(`● `+n.status);console.log(` ${Z(`Health:`)} ${e}`)}else console.log(` ${Z(`Health:`)} ${xa(`● unreachable`)}`);if(r){let e=((r.errorRate??0)*100).toFixed(1),t=r.errorRate>.1?xa:r.errorRate>0?Sa:ba;console.log(` ${Z(`Uptime:`)} ${wa(r.uptimeSeconds)}`),console.log(` ${Z(`Requests:`)} ${r.requests}`),console.log(` ${Z(`Errors:`)} ${r.serverErrors} server, ${r.clientErrors??0} client ${Q(`(`)}${t(e+`%`)}${Q(`)`)}`)}if(a&&console.log(` ${Z(`DI:`)} ${a.count} bindings`),o&&o.enabled&&console.log(` ${Z(`WS:`)} ${o.connections??0} connections, ${o.namespaces??0} namespaces`),i?.routes?.length){console.log(),console.log(Z(` Routes`)),console.log(s),console.log(` ${Q(`METHOD`)} ${Q(`PATH`.padEnd(36))} ${Q(`CONTROLLER`)}`);for(let e of i.routes){let t=e.path.length>36?e.path.slice(0,33)+`...`:e.path.padEnd(36);console.log(` ${Ct(e.method)} ${t} ${Ca(e.controller)}.${Q(e.handler)}`)}}console.log(s),console.log()}function ka(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 Da(r);t.json?console.log(JSON.stringify(e,null,2)):Oa(n,e)}catch(e){t.json?console.log(JSON.stringify({error:String(e)})):(console.error(xa(` ✖ Could not connect to ${n}`)),console.error(Q(` ${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 Aa(e,t){let n=e.toLowerCase();return t.every(e=>n.includes(e.toLowerCase()))}function $(e,t){let n=e.toLowerCase();return t.some(e=>n.includes(e.toLowerCase()))}const ja=[{match(e,t){let n=Aa(e,[`config`,`get`])&&$(e,[`undefined`,`null`]),r=e.includes(`@Value`)&&$(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
3729
2505
  registers the env schema with kickjs at module-load time. Without it,
3730
2506
  ConfigService falls back to the base schema (PORT/NODE_ENV/LOG_LEVEL only)
3731
2507
  and every user-defined key reads as undefined. @Value() may *appear* to
@@ -3737,7 +2513,7 @@ import { modules } from './modules'
3737
2513
  import './config' // ← add this — registers env schema
3738
2514
  import { bootstrap } from '@forinda/kickjs'
3739
2515
  import { modules } from './modules'
3740
- `,docs:`https://forinda.github.io/kick-js/guide/configuration.html#wiring-the-schema-at-startup`}}}},{match(e,t){let n=Q(e,[`vitest`,`test`,`spec`,`__tests__`,`.test.`]);return Q(e,[`already registered`,`already exists`,`duplicate`,`has been registered`])?{confidence:n?85:60,diagnosis:{id:`container-not-reset-in-tests`,title:`DI container leaks between test cases`,explanation:`KickJS decorators register classes on the global Container at import time.
2516
+ `,docs:`https://forinda.github.io/kick-js/guide/configuration.html#wiring-the-schema-at-startup`}}}},{match(e,t){let n=$(e,[`vitest`,`test`,`spec`,`__tests__`,`.test.`]);return $(e,[`already registered`,`already exists`,`duplicate`,`has been registered`])?{confidence:n?85:60,diagnosis:{id:`container-not-reset-in-tests`,title:`DI container leaks between test cases`,explanation:`KickJS decorators register classes on the global Container at import time.
3741
2517
  When vitest re-imports your modules across tests, the same class can be
3742
2518
  registered twice and the container throws. The fix is to wipe the
3743
2519
  container between tests so each case starts fresh.`,fix:`Add Container.reset() to a beforeEach hook in the failing test file:`,codeAfter:`import { describe, it, beforeEach } from 'vitest'
@@ -3747,7 +2523,7 @@ describe('UserController', () => {
3747
2523
  beforeEach(() => Container.reset())
3748
2524
 
3749
2525
  it('does the thing', async () => { /* ... */ })
3750
- })`,docs:`https://forinda.github.io/kick-js/guide/testing.html`}}:null}},{match(e,t){return e.includes(`@Module`)||to(e,[`Module`,`is not a function`])||to(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
2526
+ })`,docs:`https://forinda.github.io/kick-js/guide/testing.html`}}:null}},{match(e,t){return e.includes(`@Module`)||Aa(e,[`Module`,`is not a function`])||Aa(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
3751
2527
  pattern instead: a class implements AppModule and exposes routes() that
3752
2528
  returns the controller wiring. This was a deliberate choice — modules
3753
2529
  become explicit values rather than metadata, which makes them easier to
@@ -3774,7 +2550,7 @@ KickRoutes["POST /users"]. The new form is per-controller, per-method,
3774
2550
  and matches the actual class names so refactors propagate via
3775
2551
  rename-symbol instead of grep.`,fix:`Update the Ctx<...> type parameter to use the namespace form:`,codeBefore:`@Post('/', { body: createUserSchema })
3776
2552
  create(ctx: Ctx<KickRoutes['POST /users']>) { /* ... */ }`,codeAfter:`@Post('/', { body: createUserSchema, name: 'CreateUser' })
3777
- create(ctx: Ctx<KickRoutes.UserController['create']>) { /* ... */ }`,docs:`https://forinda.github.io/kick-js/guide/typegen.html`}}:null}},{match(e,t){let n=Q(e,[`cluster`,`workers`,`two ports`,`duplicate server`]),r=Q(e,[`kick dev`,`vite`,`eaddrinuse`,`5173`,`5174`,`two servers`]);return!n||!r?null:{confidence:85,diagnosis:{id:`cluster-in-vite-dev`,title:"Cluster mode is incompatible with `kick dev` (Vite owns the server)",explanation:`In dev mode, Vite owns the HTTP server. If your bootstrap passes
2553
+ create(ctx: Ctx<KickRoutes.UserController['create']>) { /* ... */ }`,docs:`https://forinda.github.io/kick-js/guide/typegen.html`}}:null}},{match(e,t){let n=$(e,[`cluster`,`workers`,`two ports`,`duplicate server`]),r=$(e,[`kick dev`,`vite`,`eaddrinuse`,`5173`,`5174`,`two servers`]);return!n||!r?null:{confidence:85,diagnosis:{id:`cluster-in-vite-dev`,title:"Cluster mode is incompatible with `kick dev` (Vite owns the server)",explanation:`In dev mode, Vite owns the HTTP server. If your bootstrap passes
3778
2554
  cluster: { workers: N }, the framework forks N workers, each of which
3779
2555
  spins up its own Vite instance on a separate port. The fix landed in
3780
2556
  v2.2.5: McpAdapter (and bootstrap()) now detects Vite dev mode and
@@ -3782,7 +2558,7 @@ silently skips cluster, with a warning. If you see this on an older
3782
2558
  version, upgrade or guard the cluster option behind NODE_ENV.`,fix:`Either upgrade to v2.2.5+ or gate cluster mode on production:`,codeAfter:`export const app = await bootstrap({
3783
2559
  modules,
3784
2560
  cluster: process.env.NODE_ENV === 'production' ? { workers: 4 } : false,
3785
- })`,docs:`https://forinda.github.io/kick-js/guide/cluster.html`}}}},{match(e,t){return Q(e,[`reflect-metadata`,`Reflect.getMetadata is not a function`,`Reflect.defineMetadata`,`design:type`,`design:paramtypes`])?{confidence:90,diagnosis:{id:`reflect-metadata-missing`,title:`reflect-metadata is not loaded — DI cannot read decorator types`,explanation:`The DI container reads constructor parameter types via the
2561
+ })`,docs:`https://forinda.github.io/kick-js/guide/cluster.html`}}}},{match(e,t){return $(e,[`reflect-metadata`,`Reflect.getMetadata is not a function`,`Reflect.defineMetadata`,`design:type`,`design:paramtypes`])?{confidence:90,diagnosis:{id:`reflect-metadata-missing`,title:`reflect-metadata is not loaded — DI cannot read decorator types`,explanation:`The DI container reads constructor parameter types via the
3786
2562
  reflect-metadata polyfill. The polyfill must be imported once,
3787
2563
  before any decorator runs. Most projects do this at the top of
3788
2564
  src/index.ts; missing the import causes obscure "design:paramtypes"
@@ -3791,7 +2567,7 @@ import './config'
3791
2567
  import { bootstrap } from '@forinda/kickjs'
3792
2568
  import { modules } from './modules'
3793
2569
 
3794
- export const app = await bootstrap({ modules })`,docs:`https://forinda.github.io/kick-js/guide/dependency-injection.html`}}:null}},{match(e,t){return Q(e,[`404`,`cannot get`,`cannot post`,`no route`])?{confidence:50,diagnosis:{id:`module-not-registered`,title:`A 404 may indicate a module is not in the modules array`,explanation:`KickJS only mounts modules listed in \`src/modules/index.ts\`. If you
2570
+ export const app = await bootstrap({ modules })`,docs:`https://forinda.github.io/kick-js/guide/dependency-injection.html`}}:null}},{match(e,t){return $(e,[`404`,`cannot get`,`cannot post`,`no route`])?{confidence:50,diagnosis:{id:`module-not-registered`,title:`A 404 may indicate a module is not in the modules array`,explanation:`KickJS only mounts modules listed in \`src/modules/index.ts\`. If you
3795
2571
  generated a module via \`kick g module foo\` but the routes don't appear,
3796
2572
  the most likely cause is that the module is missing from the exported
3797
2573
  array. The CLI usually wires this automatically, but a hand-edit can
@@ -3799,24 +2575,24 @@ drop the entry.`,fix:`Open src/modules/index.ts and verify the module is in the
3799
2575
  import { UserModule } from './users/user.module'
3800
2576
  import { TaskModule } from './tasks/task.module' // ← was this missing?
3801
2577
 
3802
- export const modules: AppModuleEntry[] = [UserModule(), TaskModule()]`,docs:`https://forinda.github.io/kick-js/guide/project-structure.html`}}:null}}];function ro(e,t){let n=null;for(let r of no){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 io(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.
2578
+ export const modules: AppModuleEntry[] = [UserModule(), TaskModule()]`,docs:`https://forinda.github.io/kick-js/guide/project-structure.html`}}:null}}];function Ma(e,t){let n=null;for(let r of ja){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 Na(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.
3803
2579
  export OPENAI_API_KEY="sk-..."
3804
2580
 
3805
2581
  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:
3806
2582
  kick add ai
3807
2583
 
3808
2584
  Or manually:
3809
- pnpm add @forinda/kickjs-ai`}}let{OpenAIProvider:i}=r,a=new i({apiKey:n,defaultChatModel:e.model??`gpt-4o-mini`}),o=ao(e.cwd),s=`Error or stack trace:\n\n${e.input.trim()}`;try{let e=oo((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 ao(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(`
3810
- `)}function oo(e){let t=[e,so(e),co(e)].filter(e=>e!==null);for(let e of t)try{let t=JSON.parse(e);if(lo(t))return t}catch{continue}return null}function so(e){let t=e.match(/```(?:json)?\s*\n([\s\S]*?)```/);return t?t[1]?.trim()??null:null}function co(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 lo(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 uo(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 mo(e,t.message);(!n||n.trim().length===0)&&(process.stderr.write(`Error: no input provided.
2585
+ pnpm add @forinda/kickjs-ai`}}let{OpenAIProvider:i}=r,a=new i({apiKey:n,defaultChatModel:e.model??`gpt-4o-mini`}),o=Pa(e.cwd),s=`Error or stack trace:\n\n${e.input.trim()}`;try{let e=Fa((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 Pa(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(`
2586
+ `)}function Fa(e){let t=[e,Ia(e),La(e)].filter(e=>e!==null);for(let e of t)try{let t=JSON.parse(e);if(Ra(t))return t}catch{continue}return null}function Ia(e){let t=e.match(/```(?:json)?\s*\n([\s\S]*?)```/);return t?t[1]?.trim()??null:null}function La(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 Ra(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 za(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 Ha(e,t.message);(!n||n.trim().length===0)&&(process.stderr.write(`Error: no input provided.
3811
2587
 
3812
2588
  Pass a message as a positional arg, --message flag, or pipe via stdin:
3813
2589
  kick explain "config.get returned undefined"
3814
2590
  pnpm test 2>&1 | kick explain
3815
- `),process.exit(1));let r=go(),i=ro(n,r);if(t.json&&i){process.stdout.write(JSON.stringify({matched:!0,...i},null,2)+`
3816
- `);return}if(i){_o(n,i.diagnosis,i.confidence);return}t.ai||(t.json&&(process.stdout.write(JSON.stringify({matched:!1},null,2)+`
3817
- `),process.exit(2)),vo(n,!1),process.exit(2));let a=await io({input:n,model:t.model,cwd:r.cwd});t.json&&(process.stdout.write(JSON.stringify(fo(a),null,2)+`
3818
- `),process.exit(a.kind===`ok`?0:2)),po(n,a),process.exit(a.kind===`ok`?0:2)})}function fo(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 po(e,t){if(t.kind===`ok`){_o(e,t.diagnosis,-1,!0);return}if(t.kind===`unavailable`){process.stdout.write(`\n Explaining: ${bo(e.trim(),200)}\n\n`),process.stdout.write(` AI fallback unavailable: ${t.reason}\n\n`),process.stdout.write(`${yo(t.suggestion,` `)}\n\n`);return}process.stdout.write(`\n Explaining: ${bo(e.trim(),200)}\n\n`),process.stdout.write(` AI fallback error: ${t.message}\n\n`)}async function mo(e,t){return e&&e.trim().length>0?e:t&&t.trim().length>0?t:process.stdin.isTTY?``:ho()}function ho(){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 go(){let e=process.cwd();return{cwd:e,hasFile:t=>r(v(e,t))}}function _o(e,t,n,r=!1){let i=bo(e.trim(),200),a=r?`AI-generated — verify before applying`:xo(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${yo(t.explanation,` `)}\n`),process.stdout.write(`\n Fix:\n${yo(t.fix,` `)}\n`),t.codeBefore&&process.stdout.write(`\n Before:\n${yo(t.codeBefore,` `)}\n`),t.codeAfter&&process.stdout.write(`\n After:\n${yo(t.codeAfter,` `)}\n`),t.docs&&process.stdout.write(`\n Docs: ${t.docs}\n`),process.stdout.write(`
3819
- `)}function vo(e,t){let n=bo(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.
2591
+ `),process.exit(1));let r=Wa(),i=Ma(n,r);if(t.json&&i){process.stdout.write(JSON.stringify({matched:!0,...i},null,2)+`
2592
+ `);return}if(i){Ga(n,i.diagnosis,i.confidence);return}t.ai||(t.json&&(process.stdout.write(JSON.stringify({matched:!1},null,2)+`
2593
+ `),process.exit(2)),Ka(n,!1),process.exit(2));let a=await Na({input:n,model:t.model,cwd:r.cwd});t.json&&(process.stdout.write(JSON.stringify(Ba(a),null,2)+`
2594
+ `),process.exit(a.kind===`ok`?0:2)),Va(n,a),process.exit(a.kind===`ok`?0:2)})}function Ba(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 Va(e,t){if(t.kind===`ok`){Ga(e,t.diagnosis,-1,!0);return}if(t.kind===`unavailable`){process.stdout.write(`\n Explaining: ${Ja(e.trim(),200)}\n\n`),process.stdout.write(` AI fallback unavailable: ${t.reason}\n\n`),process.stdout.write(`${qa(t.suggestion,` `)}\n\n`);return}process.stdout.write(`\n Explaining: ${Ja(e.trim(),200)}\n\n`),process.stdout.write(` AI fallback error: ${t.message}\n\n`)}async function Ha(e,t){return e&&e.trim().length>0?e:t&&t.trim().length>0?t:process.stdin.isTTY?``:Ua()}function Ua(){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 Wa(){let e=process.cwd();return{cwd:e,hasFile:t=>r(v(e,t))}}function Ga(e,t,n,r=!1){let i=Ja(e.trim(),200),a=r?`AI-generated — verify before applying`:Ya(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${qa(t.explanation,` `)}\n`),process.stdout.write(`\n Fix:\n${qa(t.fix,` `)}\n`),t.codeBefore&&process.stdout.write(`\n Before:\n${qa(t.codeBefore,` `)}\n`),t.codeAfter&&process.stdout.write(`\n After:\n${qa(t.codeAfter,` `)}\n`),t.docs&&process.stdout.write(`\n Docs: ${t.docs}\n`),process.stdout.write(`
2595
+ `)}function Ka(e,t){let n=Ja(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.
3820
2596
  When @forinda/kickjs-ai ships its provider implementations,
3821
2597
  this command will call the configured LLM with the error +
3822
2598
  project context and return a structured fix.
@@ -3833,12 +2609,12 @@ Pass a message as a positional arg, --message flag, or pipe via stdin:
3833
2609
  3. File an issue with the error text:
3834
2610
  https://github.com/forinda/kick-js/issues/new
3835
2611
 
3836
- `)}function yo(e,t){return e.split(`
2612
+ `)}function qa(e,t){return e.split(`
3837
2613
  `).map(e=>`${t}${e}`).join(`
3838
- `)}function bo(e,t){return e.length<=t?e:e.slice(0,t-1)+`…`}function xo(e){return e>=90?`high confidence`:e>=70?`good match`:e>=50?`medium confidence`:`low confidence — verify manually`}function So(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(Co),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(wo)}function Co(e){let t=v(e.entry);r(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],i=ne(process.execPath,n,{stdio:`inherit`,env:{...process.env,KICK_MCP_STDIO:`1`,NODE_ENV:process.env.NODE_ENV??`production`}});i.on(`error`,e=>{process.stderr.write(`Failed to start MCP server: ${e.message}\n`),process.exit(1)}),i.on(`exit`,(e,t)=>{if(t){process.kill(process.pid,t);return}process.exit(e??0)});let a=e=>{i.killed||i.kill(e)};process.on(`SIGINT`,()=>a(`SIGINT`)),process.on(`SIGTERM`,()=>a(`SIGTERM`))}function wo(e){let t=process.cwd(),n=To(t)??d(t),i=e.name??n,o=e.global?v(process.env.HOME??`.`,`.mcp.json`):v(t,e.out),s={command:`kick`,args:[`mcp`],cwd:t},c={mcpServers:{}};if(r(o))try{let e=a(o,`utf8`),t=JSON.parse(e);t&&typeof t==`object`&&t.mcpServers&&(c={mcpServers:{...t.mcpServers}})}catch(e){let t=e instanceof Error?e.message:String(e);process.stderr.write(`Error: existing ${o} is not valid JSON (${t}).\nFix the file or pass --force to overwrite the entry.\n`),process.exit(1)}c.mcpServers[i]&&!e.force&&(process.stderr.write(`Error: an entry for "${i}" already exists in ${o}.\nPass --force to overwrite it, or use --name to pick a different key.\n`),process.exit(1)),c.mcpServers[i]=s,l(o,JSON.stringify(c,null,2)+`
3839
- `,`utf8`),process.stdout.write(`\n ✓ Wrote MCP server entry "${i}" to ${o}\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 To(e){let t=v(e,`package.json`);if(!r(t))return null;try{let e=a(t,`utf8`),n=JSON.parse(e);return typeof n.name==`string`?n.name:null}catch{return null}}function Eo(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=v(t,e.entry);r(n)||(console.error(`\n Error: ${e.entry} not found.\n`),process.exit(1));let i=Oo(t,`tsx`);i||(console.error(`
2614
+ `)}function Ja(e,t){return e.length<=t?e:e.slice(0,t-1)+`…`}function Ya(e){return e>=90?`high confidence`:e>=70?`good match`:e>=50?`medium confidence`:`low confidence — verify manually`}function Xa(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(Za),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(Qa)}function Za(e){let t=v(e.entry);r(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],i=te(process.execPath,n,{stdio:`inherit`,env:{...process.env,KICK_MCP_STDIO:`1`,NODE_ENV:process.env.NODE_ENV??`production`}});i.on(`error`,e=>{process.stderr.write(`Failed to start MCP server: ${e.message}\n`),process.exit(1)}),i.on(`exit`,(e,t)=>{if(t){process.kill(process.pid,t);return}process.exit(e??0)});let a=e=>{i.killed||i.kill(e)};process.on(`SIGINT`,()=>a(`SIGINT`)),process.on(`SIGTERM`,()=>a(`SIGTERM`))}function Qa(e){let t=process.cwd(),n=$a(t)??d(t),i=e.name??n,o=e.global?v(process.env.HOME??`.`,`.mcp.json`):v(t,e.out),s={command:`kick`,args:[`mcp`],cwd:t},c={mcpServers:{}};if(r(o))try{let e=a(o,`utf8`),t=JSON.parse(e);t&&typeof t==`object`&&t.mcpServers&&(c={mcpServers:{...t.mcpServers}})}catch(e){let t=e instanceof Error?e.message:String(e);process.stderr.write(`Error: existing ${o} is not valid JSON (${t}).\nFix the file or pass --force to overwrite the entry.\n`),process.exit(1)}c.mcpServers[i]&&!e.force&&(process.stderr.write(`Error: an entry for "${i}" already exists in ${o}.\nPass --force to overwrite it, or use --name to pick a different key.\n`),process.exit(1)),c.mcpServers[i]=s,l(o,JSON.stringify(c,null,2)+`
2615
+ `,`utf8`),process.stdout.write(`\n ✓ Wrote MCP server entry "${i}" to ${o}\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 $a(e){let t=v(e,`package.json`);if(!r(t))return null;try{let e=a(t,`utf8`),n=JSON.parse(e);return typeof n.name==`string`?n.name:null}catch{return null}}function eo(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=v(t,e.entry);r(n)||(console.error(`\n Error: ${e.entry} not found.\n`),process.exit(1));let i=no(t,`tsx`);i||(console.error(`
3840
2616
  Error: tsx not found. Install it: pnpm add -D tsx
3841
- `),process.exit(1));let a=Do(n,e.entry),o=h(t,`.kick-tinker.mjs`),{writeFileSync:s,unlinkSync:c}=await import(`node:fs`);s(o,a,`utf-8`);try{let e=te(o,[],{cwd:t,execPath:i,stdio:`inherit`});await new Promise(t=>{e.on(`exit`,()=>t())})}finally{try{c(o)}catch{}}})}function Do(e,t){return`
2617
+ `),process.exit(1));let a=to(n,e.entry),o=h(t,`.kick-tinker.mjs`),{writeFileSync:s,unlinkSync:c}=await import(`node:fs`);s(o,a,`utf-8`);try{let e=ee(o,[],{cwd:t,execPath:i,stdio:`inherit`});await new Promise(t=>{e.on(`exit`,()=>t())})}finally{try{c(o)}catch{}}})}function to(e,t){return`
3842
2618
  import 'reflect-metadata'
3843
2619
 
3844
2620
  // Prevent bootstrap() from starting the HTTP server
@@ -3892,40 +2668,39 @@ server.on('exit', () => {
3892
2668
  console.log('\\n Goodbye!\\n')
3893
2669
  process.exit(0)
3894
2670
  })
3895
- `}function Oo(e,t){let n=e;for(;;){let e=h(n,`node_modules`,`.bin`,t);if(r(e))return e;let i=v(n,`..`);if(i===n)break;n=i}return null}function ko(e,t){let n=RegExp(`^\\s*${B(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]!==`
2671
+ `}function no(e,t){let n=e;for(;;){let e=h(n,`node_modules`,`.bin`,t);if(r(e))return e;let i=v(n,`..`);if(i===n)break;n=i}return null}function ro(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]!==`
3896
2672
  `;)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]===`
3897
- `);)t--;a=a.slice(0,t)+a.slice(s+1),r=!0,i=t;continue}i=s+1}return{content:a,changed:r}}function Ao(e,t){let n=nr(e);if(!n)return e;let r=n.rhsStart,i=n.rhsEnd+1,a=e.slice(r,i);return a=ko(a,t).content,a=a.replace(RegExp(`\\s*,?\\s*${B(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 jo(e){let{name:t,modulesDir:n,force:r}=e,i=e.pluralize!==!1,a=R(t),o=I(t),s=i?z(a):a,c=h(n,s);if(!await Qe(c)){console.log(`\n Module not found: ${c}\n`);return}if(!r&&!await P({message:E.red(`Delete module '${s}' at ${c}? This cannot be undone.`),initialValue:!1})){console.log(`
2673
+ `);)t--;a=a.slice(0,t)+a.slice(s+1),r=!0,i=t;continue}i=s+1}return{content:a,changed:r}}function io(e,t){let n=kn(e);if(!n)return e;let r=n.rhsStart,i=n.rhsEnd+1,a=e.slice(r,i);return a=ro(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 ao(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=h(n,s);if(!await Ue(c)){console.log(`\n Module not found: ${c}\n`);return}if(!r&&!await I({message:k.red(`Delete module '${s}' at ${c}? This cannot be undone.`),initialValue:!1})){console.log(`
3898
2674
  Cancelled.
3899
- `);return}await ce(c,{recursive:!0,force:!0}),console.log(` Deleted: ${c}`);let l=h(n,`index.ts`);if(await Qe(l)){let e=await C(l,`utf-8`),t=e,n=RegExp(`^import\\s*\\{\\s*${B(o)}Module\\s*\\}\\s*from\\s*['"][^'"]*${B(s)}(?:/[^'"]*)?['"].*\\n?`,`gm`);e=e.replace(n,``),e=Ao(e,o),e=e.replace(/\n{3,}/g,`
2675
+ `);return}await oe(c,{recursive:!0,force:!0}),console.log(` Deleted: ${c}`);let l=h(n,`index.ts`);if(await Ue(l)){let e=await T(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=io(e,o),e=e.replace(/\n{3,}/g,`
3900
2676
 
3901
- `),e!==t&&(await w(l,e,`utf-8`),console.log(` Unregistered: ${o}Module from ${l}`))}console.log(`\n Module '${s}' removed.\n`)}function Mo(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 n=O(await k(process.cwd())),r=t.modulesDir??n.dir??`src/modules`,i=t.pluralize===!1?!1:n.pluralize??!0;for(let n of e)await jo({name:n,modulesDir:v(r),force:t.force,pluralize:i})})}function No(e){if(e!==void 0){if(e===`false`||e===`off`||e===`none`)return!1;if(e===`zod`)return`zod`;if(e===`kickjs-schema`||e===`schema`)return`kickjs-schema`;console.warn(` kick typegen: unknown --schema-validator '${e}' (supported: 'zod', 'kickjs-schema', 'false'). Falling back to project config.`)}}function Po(e){if(e!==void 0)return e===`false`||e===`off`||e===`none`?!1:e}function Fo(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=en(process.cwd()),n=await k(t);if(e.list){let{mergeCliPlugins:e}=await Promise.resolve().then(()=>We),{builtinCliPlugins:t}=await Promise.resolve().then(()=>Ys),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(`
2677
+ `),e!==t&&(await E(l,e,`utf-8`),console.log(` Unregistered: ${o}Module from ${l}`))}console.log(`\n Module '${s}' removed.\n`)}function oo(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 n=j(await M(process.cwd())),r=t.modulesDir??n.dir??`src/modules`,i=t.pluralize===!1?!1:n.pluralize??!0;for(let n of e)await ao({name:n,modulesDir:v(r),force:t.force,pluralize:i})})}function so(e){if(e!==void 0){if(e===`false`||e===`off`||e===`none`)return!1;if(e===`zod`)return`zod`;if(e===`kickjs-schema`||e===`schema`)return`kickjs-schema`;console.warn(` kick typegen: unknown --schema-validator '${e}' (supported: 'zod', 'kickjs-schema', 'false'). Falling back to project config.`)}}function co(e){if(e!==void 0)return e===`false`||e===`off`||e===`none`?!1:e}function lo(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=Gt(process.cwd()),n=await M(t);if(e.list){let{mergeCliPlugins:e}=await Promise.resolve().then(()=>Fe),{builtinCliPlugins:t}=await Promise.resolve().then(()=>gs),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(`
3902
2678
  Registered typegen plugins:
3903
- `);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 r=No(e.schemaValidator)??n?.typegen?.schemaValidator??`zod`,i=Po(e.envFile)??n?.typegen?.envFile,a={cwd:t,srcDir:e.src??n?.typegen?.srcDir,outDir:e.out??n?.typegen?.outDir,silent:e.silent,allowDuplicates:e.allowDuplicates,schemaValidator:r,envFile:i,assetMap:n?.assetMap,runPlugins:!1};try{if(e.watch){let t=await xa(a);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 q(a);let r=await Fa({cwd:t,config:n??null,silent:e.silent,check:e.check});e.check&&r.some(e=>e.status===`written`)&&process.exit(1),e.check||await ba(v(t,e.out??n?.typegen?.outDir??`.kickjs/types`),r,e.silent??!1)}}catch(e){e instanceof Xi?console.error(`
2679
+ `);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 r=so(e.schemaValidator)??n?.typegen?.schemaValidator??`zod`,i=co(e.envFile)??n?.typegen?.envFile,a={cwd:t,srcDir:e.src??n?.typegen?.srcDir,outDir:e.out??n?.typegen?.outDir,silent:e.silent,allowDuplicates:e.allowDuplicates,schemaValidator:r,envFile:i,assetMap:n?.assetMap,runPlugins:!1};try{if(e.watch){let t=await qi(a);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 J(a);let r=await la({cwd:t,config:n??null,silent:e.silent,check:e.check});e.check&&r.some(e=>e.status===`written`)&&process.exit(1),e.check||await Ki(v(t,e.out??n?.typegen?.outDir??`.kickjs/types`),r,e.silent??!1)}}catch(e){e instanceof Si?console.error(`
3904
2680
  `+e.message+`
3905
- `):e instanceof Error?console.error(`\n kick typegen failed: ${e.message}`):console.error(`\n kick typegen failed: ${JSON.stringify(e)}`),process.exit(1)}})}function Io(e){let t=[];if(!r(e))return t;let n=o(e,{withFileTypes:!0});for(let r of n){let n=h(e,r.name);if(r.isDirectory()){if([`node_modules`,`dist`,`.kickjs`,`.git`].includes(r.name))continue;t.push(...Io(n))}else r.isFile()&&/\.tsx?$/.test(r.name)&&!r.name.endsWith(`.d.ts`)&&t.push(n)}return t}function Lo(e){try{return a(e,`utf-8`)}catch{return``}}const Ro=new Set([`secret`,`changeme`,`password`,`test`,`default`,``]);function zo(e,t){let n=Lo(h(e,`.env`));if(n){let e=n.match(/^JWT_SECRET\s*=\s*['"]?([^'"\n]*)['"]?/m);if(e){let t=e[1].trim();if(Ro.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 Bo(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 Vo(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 Ho(){return process.env.NODE_ENV===`production`?null:{severity:`WARNING`,message:`NODE_ENV is '${process.env.NODE_ENV??`undefined`}', not 'production'`}}function Uo(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 Wo(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 Go(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 Ko(e){let t=Io(h(e,`src`)).map(e=>Lo(e)),n=[],r=zo(e,t);r&&n.push(r);let i=Bo(t);i&&n.push(i);let a=Vo(t);a&&n.push(a);let o=Ho();o&&n.push(o);let s=Uo(t);return s&&n.push(s),n.push(Wo(t)),n.push(Go(t)),n}function qo(e){e.command(`check`).description(`Audit project for common issues`).option(`--deploy`,`Run production readiness checks`).action(e=>{if(!e.deploy){console.log(`
2681
+ `):e instanceof Error?console.error(`\n kick typegen failed: ${e.message}`):console.error(`\n kick typegen failed: ${JSON.stringify(e)}`),process.exit(1)}})}function uo(e){let t=[];if(!r(e))return t;let n=o(e,{withFileTypes:!0});for(let r of n){let n=h(e,r.name);if(r.isDirectory()){if([`node_modules`,`dist`,`.kickjs`,`.git`].includes(r.name))continue;t.push(...uo(n))}else r.isFile()&&/\.tsx?$/.test(r.name)&&!r.name.endsWith(`.d.ts`)&&t.push(n)}return t}function fo(e){try{return a(e,`utf-8`)}catch{return``}}const po=new Set([`secret`,`changeme`,`password`,`test`,`default`,``]);function mo(e,t){let n=fo(h(e,`.env`));if(n){let e=n.match(/^JWT_SECRET\s*=\s*['"]?([^'"\n]*)['"]?/m);if(e){let t=e[1].trim();if(po.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 ho(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 go(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 _o(){return process.env.NODE_ENV===`production`?null:{severity:`WARNING`,message:`NODE_ENV is '${process.env.NODE_ENV??`undefined`}', not 'production'`}}function vo(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 yo(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 bo(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 xo(e){let t=uo(h(e,`src`)).map(e=>fo(e)),n=[],r=mo(e,t);r&&n.push(r);let i=ho(t);i&&n.push(i);let a=go(t);a&&n.push(a);let o=_o();o&&n.push(o);let s=vo(t);return s&&n.push(s),n.push(yo(t)),n.push(bo(t)),n}function So(e){e.command(`check`).description(`Audit project for common issues`).option(`--deploy`,`Run production readiness checks`).action(e=>{if(!e.deploy){console.log(`
3906
2682
  Usage: kick check --deploy
3907
2683
 
3908
2684
  Available checks:
3909
2685
  --deploy Audit for production readiness (security, config, best practices)
3910
- `);return}let t=process.cwd();Pt(`KickJS Deploy Check`);let n=zt();n.start(`Scanning project...`);let r=Ko(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)F.message(`${Nt(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?E.red(`${a} critical`):`${a} critical`,o>0?E.yellow(`${o} ${c}`):`${o} ${c}`,`${s} info`].join(`, `);a>0?(N(E.red(`${l} — fix critical issues before deploying`)),process.exit(1)):N(E.green(`${l} — looking good!`))})}function Jo(e){try{return JSON.parse(a(e,`utf-8`))}catch{return null}}function Yo(e){try{return a(e,`utf-8`)}catch{return null}}function Xo(e){let t=Yo(h(e,`tsconfig.json`));if(!t)return null;let n=t.replace(/\/\*[\s\S]*?\*\//g,``).replace(/\/\/.*$/gm,``),r;try{r=JSON.parse(n)}catch{return null}if(typeof r?.extends==`string`){let t=Zo(e,r.extends);if(t){let e=Jo(t)??{};r.compilerOptions={...e.compilerOptions,...r.compilerOptions}}}return r}function Zo(e,t){if(t.startsWith(`.`)){let n=v(e,t);return r(n)?n:null}let n=h(e,`node_modules`,t);return r(n)?n:null}function Qo(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function $o(){let e=process.version,t=Number.parseInt(e.replace(/^v/,``).split(`.`)[0],10);return Number.isNaN(t)||t<20?{name:`Node version`,status:`fail`,message:e,fix:`KickJS requires Node 20 or newer.
3911
- Install a supported version via nvm / fnm / volta.`}:{name:`Node version`,status:`pass`,message:e}}function es(e){if(!e.pkg)return{name:`@forinda/kickjs installed`,status:`warn`,message:`no package.json`};let t={...e.pkg.dependencies,...e.pkg.peerDependencies};return t[`@forinda/kickjs`]?{name:`@forinda/kickjs installed`,status:`pass`,message:t[`@forinda/kickjs`]}:{name:`@forinda/kickjs installed`,status:`fail`,fix:"This directory does not look like a KickJS project — `@forinda/kickjs` is not in your package.json. Run `kick doctor` from the project root, or scaffold a fresh project with `kick new <name>`."}}function ts(e){if(!e.pkg)return null;let t={...e.pkg.dependencies,...e.pkg.peerDependencies};return t[`@forinda/kickjs`]&&!t.express?{name:`express installed`,status:`fail`,fix:"`@forinda/kickjs` declares `express` as a required peer dependency, but your package.json does not include it. Install: pnpm add express"}:t.express?{name:`express installed`,status:`pass`,message:t.express}:null}function ns(e){if(!e.pkg)return{name:`reflect-metadata installed`,status:`warn`,message:`no package.json`};let t={...e.pkg.dependencies,...e.pkg.peerDependencies,...e.pkg.devDependencies};return t[`reflect-metadata`]?{name:`reflect-metadata installed`,status:`pass`,message:t[`reflect-metadata`]}:{name:`reflect-metadata installed`,status:`fail`,fix:`KickJS decorators require the reflect-metadata polyfill.
2686
+ `);return}let t=process.cwd();Tt(`KickJS Deploy Check`);let n=At();n.start(`Scanning project...`);let r=xo(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)L.message(`${wt(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?(F(k.red(`${l} — fix critical issues before deploying`)),process.exit(1)):F(k.green(`${l} — looking good!`))})}function Co(e){try{return JSON.parse(a(e,`utf-8`))}catch{return null}}function wo(e){try{return a(e,`utf-8`)}catch{return null}}function To(e){let t=wo(h(e,`tsconfig.json`));if(!t)return null;let n=t.replace(/\/\*[\s\S]*?\*\//g,``).replace(/\/\/.*$/gm,``),r;try{r=JSON.parse(n)}catch{return null}if(typeof r?.extends==`string`){let t=Eo(e,r.extends);if(t){let e=Co(t)??{};r.compilerOptions={...e.compilerOptions,...r.compilerOptions}}}return r}function Eo(e,t){if(t.startsWith(`.`)){let n=v(e,t);return r(n)?n:null}let n=h(e,`node_modules`,t);return r(n)?n:null}function Do(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function Oo(){let e=process.version,t=Number.parseInt(e.replace(/^v/,``).split(`.`)[0],10);return Number.isNaN(t)||t<20?{name:`Node version`,status:`fail`,message:e,fix:`KickJS requires Node 20 or newer.
2687
+ Install a supported version via nvm / fnm / volta.`}:{name:`Node version`,status:`pass`,message:e}}function ko(e){if(!e.pkg)return{name:`@forinda/kickjs installed`,status:`warn`,message:`no package.json`};let t={...e.pkg.dependencies,...e.pkg.peerDependencies};return t[`@forinda/kickjs`]?{name:`@forinda/kickjs installed`,status:`pass`,message:t[`@forinda/kickjs`]}:{name:`@forinda/kickjs installed`,status:`fail`,fix:"This directory does not look like a KickJS project — `@forinda/kickjs` is not in your package.json. Run `kick doctor` from the project root, or scaffold a fresh project with `kick new <name>`."}}function Ao(e){if(!e.pkg)return null;let t={...e.pkg.dependencies,...e.pkg.peerDependencies};return t[`@forinda/kickjs`]&&!t.express?{name:`express installed`,status:`fail`,fix:"`@forinda/kickjs` declares `express` as a required peer dependency, but your package.json does not include it. Install: pnpm add express"}:t.express?{name:`express installed`,status:`pass`,message:t.express}:null}function jo(e){if(!e.pkg)return{name:`reflect-metadata installed`,status:`warn`,message:`no package.json`};let t={...e.pkg.dependencies,...e.pkg.peerDependencies,...e.pkg.devDependencies};return t[`reflect-metadata`]?{name:`reflect-metadata installed`,status:`pass`,message:t[`reflect-metadata`]}:{name:`reflect-metadata installed`,status:`fail`,fix:`KickJS decorators require the reflect-metadata polyfill.
3912
2688
  Install it: pnpm add reflect-metadata
3913
2689
  Then import it at the top of src/index.ts:
3914
2690
 
3915
2691
  import 'reflect-metadata'
3916
- // ... rest of bootstrap`}}function rs(e){if(!e.tsconfig)return[{name:`tsconfig.json present`,status:`fail`,fix:"Create a tsconfig.json with `experimentalDecorators: true` and `emitDecoratorMetadata: true`. `kick new` scaffolds one automatically."}];let t=e.tsconfig.compilerOptions??{},n=[];return n.push(t.experimentalDecorators===!0?{name:`tsconfig: experimentalDecorators`,status:`pass`}:{name:`tsconfig: experimentalDecorators`,status:`fail`,fix:'Add `"experimentalDecorators": true` to compilerOptions in tsconfig.json. Without it, @Service / @Controller / @Get etc. don\'t register any metadata at compile time.'}),n.push(t.emitDecoratorMetadata===!0?{name:`tsconfig: emitDecoratorMetadata`,status:`pass`}:{name:`tsconfig: emitDecoratorMetadata`,status:`fail`,fix:'Add `"emitDecoratorMetadata": true` to compilerOptions in tsconfig.json. The DI container uses this metadata for constructor-parameter injection.'}),n}function is(e){let t=[`src/env.ts`,`src/env/index.ts`,`src/config/env.ts`,`src/config/index.ts`].map(t=>h(e.cwd,t)).filter(e=>r(e)).filter(e=>/\bloadEnv\s*\(/.test(Yo(e)??``));if(t.length===0)return null;let n=[`src/index.ts`,`src/main.ts`].map(t=>h(e.cwd,t)).find(e=>r(e));if(!n)return{name:`env wiring`,status:`warn`,message:`env-init file exists but no src/index.ts or src/main.ts found`};let i=Yo(n)??``,a=f(n),o=[];for(let e of t){let t=_(a,e).replace(/\\/g,`/`).replace(/\.ts$/,``),n=t.startsWith(`.`)?t:`./`+t,r=n.replace(/\/index$/,``);o.push(n,r);let i=e.replace(/\\/g,`/`).match(/\/src\/(.+?)(?:\.ts)?$/);if(i){let e=`@/`+i[1],t=e.replace(/\/index$/,``);o.push(e,t)}}let s=-1;for(let e of new Set(o)){let t=RegExp(`^import\\s+(?:.*?from\\s+)?['"]${Qo(e)}['"]`,`m`),n=i.match(t);n&&n.index!==void 0&&(s===-1||n.index<s)&&(s=n.index)}let c=i.search(/\bbootstrap\s*\(/),l=t.map(t=>_(e.cwd,t).replace(/\\/g,`/`)).join(`, `);return s===-1?{name:`env wiring`,status:`fail`,message:l,fix:`An env-init file (${l}) calls \`loadEnv(...)\` but \`${_(e.cwd,n).replace(/\\/g,`/`)}\` doesn't import it.\nWithout this, ConfigService.get('X') returns undefined while @Value('X') works via process.env fallback — a half-broken config you won't notice until something is missing.\n\nFix: add a side-effect import at the top of ${_(e.cwd,n).replace(/\\/g,`/`)} (above bootstrap()), pointing at one of the detected files. For example:\n\n import './env'\n // or\n import './config'\n // or, with the @/ alias:\n import '@/config/env'`}:c!==-1&&s>c?{name:`env wiring`,status:`warn`,message:`env-init imported AFTER bootstrap() — should be before`,fix:`Move the env import above the bootstrap() call so the schema runs before any service reads from ConfigService.`}:{name:`env wiring`,status:`pass`}}function as(e,t=os){let n=0,r=0,i=[e];for(;i.length>0&&r<t;){let e=i.pop(),a;try{a=o(e,{withFileTypes:!0})}catch{continue}for(let o of a){if(r>=t)break;r++;let a=h(e,o.name);if(o.isDirectory()){i.push(a);continue}try{let e=c(a).mtimeMs;e>n&&(n=e)}catch{}}}return n}const os=2e3;function ss(e){let t=h(e.cwd,`.kickjs`,`types`);if(!r(t))return null;let n=as(t);if(n===0)return null;let i=Date.now()-n,a=Math.floor(i/6e4);return a>60?{name:`typegen freshness`,status:`warn`,message:`last updated ${a} minutes ago`,fix:"Re-run `kick typegen` (or `kick dev`, which runs it on every reload) so generated types match the current code."}:{name:`typegen freshness`,status:`pass`,message:a===0?`just now`:`${a}m ago`}}const cs=[()=>$o(),es,ts,ns,rs,is,ss];async function ls(e,t={}){let n={cwd:e,pkg:Jo(h(e,`package.json`)),tsconfig:Xo(e)},r=[...cs,...t.extraChecks??[]],i=[];for(let e of r){let t;try{t=await e(n)}catch(t){i.push({name:e.name||`doctor check`,status:`fail`,message:t instanceof Error?t.message:String(t)});continue}t!=null&&(Array.isArray(t)?i.push(...t):i.push(t))}return i}function us(e){switch(e){case`pass`:return E.green(`✔`);case`warn`:return E.yellow(`⚠`);case`fail`:return E.red(`✖`)}}function ds(e){let t=us(e.status),n=e.message?` ${E.dim(`(${e.message})`)}`:``;return`${t} ${e.name}${n}`}function fs(e){return e.split(`
3917
- `).map(e=>` ${E.dim(`→`)} ${e}`).join(`
3918
- `)}function ps(e){return e?.doctor?.checks??[]}function ms(e){e.command(`doctor`).description(`Pre-flight checks for your KickJS project (dev environment health)`).action(async()=>{let e=process.cwd(),t=ps(await k(e));Pt(`KickJS Doctor`);let n=await ls(e,{extraChecks:t});for(let e of n)F.message(ds(e)),e.fix&&e.status!==`pass`&&F.message(fs(e.fix));let r=n.filter(e=>e.status===`pass`).length,i=n.filter(e=>e.status===`warn`).length,a=n.filter(e=>e.status===`fail`).length,o=[E.green(`${r} passed`),i>0?E.yellow(`${i} warning${i===1?``:`s`}`):`${i} warnings`,a>0?E.red(`${a} error${a===1?``:`s`}`):`${a} errors`].join(`, `);a>0?(N(`${o} — fix the errors above before running the app`),process.exit(1)):N(i>0?`${o} — review the warnings`:E.green(`${o} — your environment looks good`))})}async function $(e){return Ee({configPath:u.resolve(process.cwd(),e.config)})}async function hs(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()}}}async function gs(e){if(e.adapter||(e.dialect??`postgres`)!==`postgres`||!e.connectionString)return null;let t=new(await(import(`pg`))).default.Pool({connectionString:e.connectionString});return{runner:t,cleanup:async()=>{await t.end()}}}function _s(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 vs(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 $(t),i=await gs(r),a=i?e=>ve(i.runner,e):void 0;try{let i=await ye({name:e,config:r,cwd:n,empty:t.empty,detectCompositeRefs:a});if(i.status===`no-changes`){console.log(`No schema changes detected.`);return}if(i.empty){console.log(`Created empty migration ${i.migrationDir} (author up.sql + down.sql).`);return}let o=i.changeCount===1?``:`s`;console.log(`Created migration ${i.migrationDir} (${i.changeCount} change${o}).`)}finally{await i?.cleanup()}});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 $(e),{adapter:n,cleanup:r}=await hs(t);try{let r=await xe({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 $(e),{adapter:n,cleanup:r}=await hs(t);try{let r=await we({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 $(e),{adapter:n,cleanup:r}=await hs(t);try{let e=await be({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 $(e),{adapter:n,cleanup:r}=await hs(t);try{let e=await Se({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 $(e),{adapter:n,cleanup:r}=await hs(t);try{_s(await Ce({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 $(e),{adapter:n,cleanup:r}=await hs(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 w(i,Te(r),`utf8`);let a=Object.keys(r.tables).length;console.log(`Wrote ${i} (${a} table${a===1?``:`s`}).`)}finally{await r()}})}function ys(e){return e.optsWithGlobals().dryRun??!1}function bs(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.
2692
+ // ... rest of bootstrap`}}function Mo(e){if(!e.tsconfig)return[{name:`tsconfig.json present`,status:`fail`,fix:"Create a tsconfig.json with `experimentalDecorators: true` and `emitDecoratorMetadata: true`. `kick new` scaffolds one automatically."}];let t=e.tsconfig.compilerOptions??{},n=[];return n.push(t.experimentalDecorators===!0?{name:`tsconfig: experimentalDecorators`,status:`pass`}:{name:`tsconfig: experimentalDecorators`,status:`fail`,fix:'Add `"experimentalDecorators": true` to compilerOptions in tsconfig.json. Without it, @Service / @Controller / @Get etc. don\'t register any metadata at compile time.'}),n.push(t.emitDecoratorMetadata===!0?{name:`tsconfig: emitDecoratorMetadata`,status:`pass`}:{name:`tsconfig: emitDecoratorMetadata`,status:`fail`,fix:'Add `"emitDecoratorMetadata": true` to compilerOptions in tsconfig.json. The DI container uses this metadata for constructor-parameter injection.'}),n}function No(e){let t=[`src/env.ts`,`src/env/index.ts`,`src/config/env.ts`,`src/config/index.ts`].map(t=>h(e.cwd,t)).filter(e=>r(e)).filter(e=>/\bloadEnv\s*\(/.test(wo(e)??``));if(t.length===0)return null;let n=[`src/index.ts`,`src/main.ts`].map(t=>h(e.cwd,t)).find(e=>r(e));if(!n)return{name:`env wiring`,status:`warn`,message:`env-init file exists but no src/index.ts or src/main.ts found`};let i=wo(n)??``,a=f(n),o=[];for(let e of t){let t=_(a,e).replace(/\\/g,`/`).replace(/\.ts$/,``),n=t.startsWith(`.`)?t:`./`+t,r=n.replace(/\/index$/,``);o.push(n,r);let i=e.replace(/\\/g,`/`).match(/\/src\/(.+?)(?:\.ts)?$/);if(i){let e=`@/`+i[1],t=e.replace(/\/index$/,``);o.push(e,t)}}let s=-1;for(let e of new Set(o)){let t=RegExp(`^import\\s+(?:.*?from\\s+)?['"]${Do(e)}['"]`,`m`),n=i.match(t);n&&n.index!==void 0&&(s===-1||n.index<s)&&(s=n.index)}let c=i.search(/\bbootstrap\s*\(/),l=t.map(t=>_(e.cwd,t).replace(/\\/g,`/`)).join(`, `);return s===-1?{name:`env wiring`,status:`fail`,message:l,fix:`An env-init file (${l}) calls \`loadEnv(...)\` but \`${_(e.cwd,n).replace(/\\/g,`/`)}\` doesn't import it.\nWithout this, ConfigService.get('X') returns undefined while @Value('X') works via process.env fallback — a half-broken config you won't notice until something is missing.\n\nFix: add a side-effect import at the top of ${_(e.cwd,n).replace(/\\/g,`/`)} (above bootstrap()), pointing at one of the detected files. For example:\n\n import './env'\n // or\n import './config'\n // or, with the @/ alias:\n import '@/config/env'`}:c!==-1&&s>c?{name:`env wiring`,status:`warn`,message:`env-init imported AFTER bootstrap() — should be before`,fix:`Move the env import above the bootstrap() call so the schema runs before any service reads from ConfigService.`}:{name:`env wiring`,status:`pass`}}function Po(e,t=Fo){let n=0,r=0,i=[e];for(;i.length>0&&r<t;){let e=i.pop(),a;try{a=o(e,{withFileTypes:!0})}catch{continue}for(let o of a){if(r>=t)break;r++;let a=h(e,o.name);if(o.isDirectory()){i.push(a);continue}try{let e=c(a).mtimeMs;e>n&&(n=e)}catch{}}}return n}const Fo=2e3;function Io(e){let t=h(e.cwd,`.kickjs`,`types`);if(!r(t))return null;let n=Po(t);if(n===0)return null;let i=Date.now()-n,a=Math.floor(i/6e4);return a>60?{name:`typegen freshness`,status:`warn`,message:`last updated ${a} minutes ago`,fix:"Re-run `kick typegen` (or `kick dev`, which runs it on every reload) so generated types match the current code."}:{name:`typegen freshness`,status:`pass`,message:a===0?`just now`:`${a}m ago`}}const Lo=[()=>Oo(),ko,Ao,jo,Mo,No,Io];async function Ro(e,t={}){let n={cwd:e,pkg:Co(h(e,`package.json`)),tsconfig:To(e)},r=[...Lo,...t.extraChecks??[]],i=[];for(let e of r){let t;try{t=await e(n)}catch(t){i.push({name:e.name||`doctor check`,status:`fail`,message:t instanceof Error?t.message:String(t)});continue}t!=null&&(Array.isArray(t)?i.push(...t):i.push(t))}return i}function zo(e){switch(e){case`pass`:return k.green(`✔`);case`warn`:return k.yellow(`⚠`);case`fail`:return k.red(`✖`)}}function Bo(e){let t=zo(e.status),n=e.message?` ${k.dim(`(${e.message})`)}`:``;return`${t} ${e.name}${n}`}function Vo(e){return e.split(`
2693
+ `).map(e=>` ${k.dim(`→`)} ${e}`).join(`
2694
+ `)}function Ho(e){return e?.doctor?.checks??[]}function Uo(e){e.command(`doctor`).description(`Pre-flight checks for your KickJS project (dev environment health)`).action(async()=>{let e=process.cwd(),t=Ho(await M(e));Tt(`KickJS Doctor`);let n=await Ro(e,{extraChecks:t});for(let e of n)L.message(Bo(e)),e.fix&&e.status!==`pass`&&L.message(Vo(e.fix));let r=n.filter(e=>e.status===`pass`).length,i=n.filter(e=>e.status===`warn`).length,a=n.filter(e=>e.status===`fail`).length,o=[k.green(`${r} passed`),i>0?k.yellow(`${i} warning${i===1?``:`s`}`):`${i} warnings`,a>0?k.red(`${a} error${a===1?``:`s`}`):`${a} errors`].join(`, `);a>0?(F(`${o} — fix the errors above before running the app`),process.exit(1)):F(i>0?`${o} — review the warnings`:k.green(`${o} — your environment looks good`))})}function Wo(e){return e.optsWithGlobals().dryRun??!1}function Go(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.
3919
2695
  Direction defaults to \`modules.style\` from kick.config (or "define").
3920
2696
  --target define|class Override the migration direction.
3921
2697
  --apply Apply the changes (default: dry-run preview).
3922
- --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 n=ys(t)||!e.apply;j(n),e.experimental||(console.error(`
3923
- `+E.red(`Error:`)+` kick codemod modules is experimental — pass --experimental to acknowledge.
2698
+ --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 n=Wo(t)||!e.apply;N(n),e.experimental||(console.error(`
2699
+ `+k.red(`Error:`)+` kick codemod modules is experimental — pass --experimental to acknowledge.
3924
2700
  The regex-based rewrite handles the shapes our templates produce.
3925
2701
  Hand-rolled modules with non-standard structures may be skipped.
3926
2702
  Always commit before running with --apply.
3927
- `),process.exit(1));let r=O(await k(process.cwd())),i=v(e.modulesDir??r.dir??`src/modules`),a;e.target===`define`||e.target===`class`?a=e.target:e.target===void 0?a=r.style??`define`:(console.error(`\n ${E.red(`Error:`)} --target must be 'define' or 'class' (got '${e.target}').\n`),process.exit(1));let o=E.dim(`→ ${a}`),s=n?E.dim(`(dry-run)`):E.bold(`(applying)`);console.log(`\n ${E.bold(`kick codemod modules`)} ${o} ${s}`),console.log(` modulesDir: ${E.dim(i)}\n`);let c=e.backup!==!1&&!n,l=await Rr(i,{dryRun:n,target:a,backup:c});if(l.backupDir){let e=l.backupDir;console.log(` ${E.green(`✓`)} backup: ${E.dim(e)}\n ${E.dim(`(restore: rm -rf <modulesDir> && mv "<backup>" <modulesDir>)`)}\n`)}else !n&&e.backup===!1&&console.log(` ${E.dim(`(--no-backup — skipping snapshot)`)}\n`);let u=0,d=0;for(let e of l.files)if(e.status===`migrated`)u++,console.log(` ${E.green(`✓`)} ${e.path}`);else{d++;let t=E.dim(`(${e.reason??`skipped`})`);console.log(` ${E.dim(`-`)} ${e.path} ${t}`)}if(console.log(),l.indexStatus===`migrated`)console.log(` ${E.green(`✓`)} ${l.indexPath}`);else if(l.indexStatus===`skipped`){let e=E.dim(`(${l.indexReason??`skipped`})`);console.log(` ${E.dim(`-`)} ${l.indexPath} ${e}`)}else console.log(` ${E.dim(`-`)} ${l.indexPath} ${E.dim(`(not found)`)}`);let f=n?E.dim(` (dry-run — pass --apply to write)`):``;console.log(`\n ${E.bold(String(u))} migrated, ${E.bold(String(d))} skipped${f}\n`)})}const xs=[`src/db/schema.ts`,`src/db/schema/index.ts`,`src/db/schema`],Ss=()=>({id:`kick/db`,inputs:[`src/db/schema.ts`,`src/db/schema/**/*.ts`],async generate(e){let t=Cs(e.cwd);if(!t)return null;let n=u.resolve(e.cwd,`.kickjs/types`);return[`import type { SchemaToTypes, SchemaToRelationsRegister, KickDbClient } from '@forinda/kickjs-db'`,`import type * as appSchema from '${ws(u.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(`
3928
- `)}});function Cs(e){for(let t of xs){let n=u.resolve(e,t);if(t.endsWith(`.ts`)){if(r(n))return n}else{let e=u.join(n,`index.ts`);if(r(e))return e}}return null}function ws(e){return e.replace(/\\/g,`/`)}const Ts=()=>({id:`kick/assets`,inputs:[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`],async generate(e){if(!r(u.resolve(e.cwd,`kick.config.ts`)))return null;let t=await k(e.cwd);if(!t?.assetMap)return null;let n=da(t.assetMap,e.cwd);return n.count===0?null:fa(n)}}),Es="/* 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 Ds(e,t,n){if(e.length===0)return`${Es}
2703
+ `),process.exit(1));let r=j(await M(process.cwd())),i=v(e.modulesDir??r.dir??`src/modules`),a;e.target===`define`||e.target===`class`?a=e.target:e.target===void 0?a=r.style??`define`:(console.error(`\n ${k.red(`Error:`)} --target must be 'define' or 'class' (got '${e.target}').\n`),process.exit(1));let o=k.dim(`→ ${a}`),s=n?k.dim(`(dry-run)`):k.bold(`(applying)`);console.log(`\n ${k.bold(`kick codemod modules`)} ${o} ${s}`),console.log(` modulesDir: ${k.dim(i)}\n`);let c=e.backup!==!1&&!n,l=await lr(i,{dryRun:n,target:a,backup:c});if(l.backupDir){let e=l.backupDir;console.log(` ${k.green(`✓`)} backup: ${k.dim(e)}\n ${k.dim(`(restore: rm -rf <modulesDir> && mv "<backup>" <modulesDir>)`)}\n`)}else !n&&e.backup===!1&&console.log(` ${k.dim(`(--no-backup — skipping snapshot)`)}\n`);let u=0,d=0;for(let e of l.files)if(e.status===`migrated`)u++,console.log(` ${k.green(`✓`)} ${e.path}`);else{d++;let t=k.dim(`(${e.reason??`skipped`})`);console.log(` ${k.dim(`-`)} ${e.path} ${t}`)}if(console.log(),l.indexStatus===`migrated`)console.log(` ${k.green(`✓`)} ${l.indexPath}`);else if(l.indexStatus===`skipped`){let e=k.dim(`(${l.indexReason??`skipped`})`);console.log(` ${k.dim(`-`)} ${l.indexPath} ${e}`)}else console.log(` ${k.dim(`-`)} ${l.indexPath} ${k.dim(`(not found)`)}`);let f=n?k.dim(` (dry-run — pass --apply to write)`):``;console.log(`\n ${k.bold(String(u))} migrated, ${k.bold(String(d))} skipped${f}\n`)})}const Ko=()=>({id:`kick/assets`,inputs:[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`],async generate(e){if(!r(u.resolve(e.cwd,`kick.config.ts`)))return null;let t=await M(e.cwd);if(!t?.assetMap)return null;let n=Li(t.assetMap,e.cwd);return n.count===0?null:Ri(n)}}),qo="/* 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 Jo(e,t,n){if(e.length===0)return`${qo}
3929
2704
  // (no routes discovered yet — annotate a controller method with
3930
2705
  // @Get/@Post/@Put/@Delete/@Patch and re-run \`kick typegen\`)
3931
2706
  declare global {
@@ -3934,8 +2709,8 @@ declare global {
3934
2709
  }
3935
2710
 
3936
2711
  export {}
3937
- `;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=As(e,r,t,n,i);return a?n===`kickjs-schema`?`import('@forinda/kickjs-schema').InferSchemaOutput<typeof ${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??Os(e),l=ks(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(`
3938
- `))}return`${Es}${js(i)}
2712
+ `;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=Zo(e,r,t,n,i);return a?n===`kickjs-schema`?`import('@forinda/kickjs-schema').InferSchemaOutput<typeof ${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??Yo(e),l=Xo(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(`
2713
+ `))}return`${qo}${Qo(i)}
3939
2714
  declare global {
3940
2715
  // eslint-disable-next-line @typescript-eslint/no-namespace
3941
2716
  namespace KickRoutes {
@@ -3945,9 +2720,9 @@ ${o.join(`
3945
2720
  }
3946
2721
 
3947
2722
  export {}
3948
- `}function Os(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 ks(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 As(e,t,n,r,i){if(!e||r===!1||e.source===null)return null;let a=Ms(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 js(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(`
2723
+ `}function Yo(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 Xo(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 Zo(e,t,n,r,i){if(!e||r===!1||e.source===null)return null;let a=$o(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 Qo(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(`
3949
2724
  `)+`
3950
- `}function Ms(e,t,n){if(e===null)return`unknown`;let r=f(n);if(e===``){let e=_(r,t).split(y).join(`/`);return e=e.replace(/\.(ts|tsx|mts|cts)$/i,``),e.startsWith(`.`)||(e=`./`+e),e}if(!e.startsWith(`.`)&&!e.startsWith(`/`))return e;let i=_(r,v(f(t),e)).split(y).join(`/`);return i=i.replace(/\.(ts|tsx|mts|cts)$/i,``),i.startsWith(`.`)||(i=`./`+i),i}const Ns=()=>({id:`kick/routes`,outExtension:`.ts`,inputs:[`src/**/*.controller.ts`,`src/**/*.module.ts`],async generate(e){let t=await e.getScanResult({root:Ps(e),cwd:e.cwd,envFile:Fs(e)}),n=e.config?.typegen?.schemaValidator??`zod`,r=u.resolve(e.cwd,`.kickjs/types/kick__routes.ts`);return Ds(t.routes,r,n)}});function Ps(e){return u.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function Fs(e){let t=e.config?.typegen?.envFile;if(t!==!1)return t}function Is(e,t,n=`zod`){if(!e)return null;let r=_(f(t),e.filePath).split(y).join(`/`);return r=r.replace(/\.(ts|tsx|mts|cts)$/i,``),r.startsWith(`.`)||(r=`./`+r),`/* eslint-disable */
2725
+ `}function $o(e,t,n){if(e===null)return`unknown`;let r=f(n);if(e===``){let e=_(r,t).split(y).join(`/`);return e=e.replace(/\.(ts|tsx|mts|cts)$/i,``),e.startsWith(`.`)||(e=`./`+e),e}if(!e.startsWith(`.`)&&!e.startsWith(`/`))return e;let i=_(r,v(f(t),e)).split(y).join(`/`);return i=i.replace(/\.(ts|tsx|mts|cts)$/i,``),i.startsWith(`.`)||(i=`./`+i),i}const es=()=>({id:`kick/routes`,outExtension:`.ts`,inputs:[`src/**/*.controller.ts`,`src/**/*.module.ts`],async generate(e){let t=await e.getScanResult({root:ts(e),cwd:e.cwd,envFile:ns(e)}),n=e.config?.typegen?.schemaValidator??`zod`,r=u.resolve(e.cwd,`.kickjs/types/kick__routes.ts`);return Jo(t.routes,r,n)}});function ts(e){return u.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function ns(e){let t=e.config?.typegen?.envFile;if(t!==!1)return t}function rs(e,t,n=`zod`){if(!e)return null;let r=_(f(t),e.filePath).split(y).join(`/`);return r=r.replace(/\.(ts|tsx|mts|cts)$/i,``),r.startsWith(`.`)||(r=`./`+r),`/* eslint-disable */
3951
2726
  // AUTO-GENERATED by \`kick typegen\`. DO NOT EDIT.
3952
2727
  // Re-run with \`kick typegen\` or rely on \`kick dev\` to refresh.
3953
2728
 
@@ -3985,4 +2760,4 @@ declare global {
3985
2760
  }
3986
2761
 
3987
2762
  export {}
3988
- `}const Ls=()=>({id:`kick/env`,outExtension:`.ts`,inputs:[`src/env.ts`,`src/**/env.ts`,`src/**/*.env.ts`],async generate(e){let t=zs(e);if(t===!1)return null;let n=await e.getScanResult({root:Rs(e),cwd:e.cwd,envFile:t});if(!n.env)return null;let r=e.config?.typegen?.schemaValidator??`zod`,i=u.resolve(e.cwd,`.kickjs/types/kick__env.ts`);return Is(n.env,i,r)}});function Rs(e){return u.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function zs(e){return e.config?.typegen?.envFile}function Bs(e){return u.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function Vs(e){let t=e.config?.typegen?.envFile;if(t!==!1)return t}function Hs(e){return{root:Bs(e),cwd:e.cwd,envFile:Vs(e)}}const Us=()=>({id:`kick/registry`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult(Hs(e)),n=u.resolve(e.cwd,`.kickjs/types/kick__registry.d.ts`),r=new Set(t.collisions.map(e=>e.className));return ea(t.classes,n,r)}}),Ws=()=>({id:`kick/services`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult(Hs(e)),n=new Set(t.collisions.map(e=>e.className));return ra(`ServiceToken`,ia(t.classes,t.tokens,t.injects,n),"(no tokens discovered — declare with createToken<T>() or `kick g service <name>`)")}}),Gs=()=>({id:`kick/modules`,inputs:[`src/**/*.ts`],async generate(e){return ra(`ModuleToken`,aa((await e.getScanResult(Hs(e))).classes),"(no @Module classes discovered — `kick g module <name>` to add one)")}}),Ks=()=>({id:`kick/plugins`,inputs:[`src/**/*.ts`],async generate(e){return oa((await e.getScanResult(Hs(e))).pluginsAndAdapters)}}),qs=()=>({id:`kick/augmentations`,inputs:[`src/**/*.ts`],async generate(e){return sa((await e.getScanResult(Hs(e))).augmentations)}}),Js=()=>({id:`kick/context`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult(Hs(e));return t.contextKeys.length===0?null:na(t.contextKeys)}});var Ys=D({builtinCliPlugins:()=>Xs});const Xs=[A({name:`kick/init`,register:Xt}),A({name:`kick/generate`,register:ka}),A({name:`kick/run`,register:Ua}),A({name:`kick/info`,register:Wa}),A({name:`kick/inspect`,register:eo}),A({name:`kick/add`,register:Jt}),A({name:`kick/list`,register:qt}),A({name:`kick/explain`,register:uo}),A({name:`kick/mcp`,register:So}),A({name:`kick/tinker`,register:Eo}),A({name:`kick/remove`,register:Mo}),A({name:`kick/typegen`,register:Fo}),A({name:`kick/check`,register:qo}),A({name:`kick/doctor`,register:ms}),A({name:`kick/db`,register:vs,typegens:[Ss()]}),A({name:`kick/codemod`,register:bs}),A({name:`kick/registry`,typegens:[Us()]}),A({name:`kick/services`,typegens:[Ws()]}),A({name:`kick/modules`,typegens:[Gs()]}),A({name:`kick/plugins`,typegens:[Ks()]}),A({name:`kick/augmentations`,typegens:[qs()]}),A({name:`kick/context`,typegens:[Js()]}),A({name:`kick/assets`,typegens:[Ts()]}),A({name:`kick/routes`,typegens:[Ns()]}),A({name:`kick/env`,typegens:[Ls()]})],Zs=f(b(import.meta.url)),Qs=JSON.parse(a(h(Zs,`..`,`package.json`),`utf-8`));async function $s(){let e=new t;e.name(`kick`).description(`KickJS — A production-grade, decorator-driven Node.js framework`).version(Qs.version);let n=en(process.cwd()),r=n,i=await k(r)??{},a=Ue([...Xs,...i.plugins??[]],i.commands??[]);await a.register(e,{cwd:r,projectRoot:n,config:i,log:e=>console.log(e)}),Ae(e,{...i,commands:a.commands}),e.showHelpAfterError(),await e.parseAsync(process.argv)}$s().catch(e=>{console.error(e instanceof Error?e.message:e),process.exitCode=1});export{};
2763
+ `}const is=()=>({id:`kick/env`,outExtension:`.ts`,inputs:[`src/env.ts`,`src/**/env.ts`,`src/**/*.env.ts`],async generate(e){let t=os(e);if(t===!1)return null;let n=await e.getScanResult({root:as(e),cwd:e.cwd,envFile:t});if(!n.env)return null;let r=e.config?.typegen?.schemaValidator??`zod`,i=u.resolve(e.cwd,`.kickjs/types/kick__env.ts`);return rs(n.env,i,r)}});function as(e){return u.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function os(e){return e.config?.typegen?.envFile}function ss(e){return u.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function cs(e){let t=e.config?.typegen?.envFile;if(t!==!1)return t}function ls(e){return{root:ss(e),cwd:e.cwd,envFile:cs(e)}}const us=()=>({id:`kick/registry`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult(ls(e)),n=u.resolve(e.cwd,`.kickjs/types/kick__registry.d.ts`),r=new Set(t.collisions.map(e=>e.className));return Ei(t.classes,n,r)}}),ds=()=>({id:`kick/services`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult(ls(e)),n=new Set(t.collisions.map(e=>e.className));return ki(`ServiceToken`,Ai(t.classes,t.tokens,t.injects,n),"(no tokens discovered — declare with createToken<T>() or `kick g service <name>`)")}}),fs=()=>({id:`kick/modules`,inputs:[`src/**/*.ts`],async generate(e){return ki(`ModuleToken`,ji((await e.getScanResult(ls(e))).classes),"(no @Module classes discovered — `kick g module <name>` to add one)")}}),ps=()=>({id:`kick/plugins`,inputs:[`src/**/*.ts`],async generate(e){return Mi((await e.getScanResult(ls(e))).pluginsAndAdapters)}}),ms=()=>({id:`kick/augmentations`,inputs:[`src/**/*.ts`],async generate(e){return Ni((await e.getScanResult(ls(e))).augmentations)}}),hs=()=>({id:`kick/context`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult(ls(e));return t.contextKeys.length===0?null:Oi(t.contextKeys)}});var gs=A({builtinCliPlugins:()=>_s});const _s=[D({name:`kick/init`,register:Vt}),D({name:`kick/generate`,register:na}),D({name:`kick/run`,register:va}),D({name:`kick/info`,register:ya}),D({name:`kick/inspect`,register:ka}),D({name:`kick/add`,register:zt}),D({name:`kick/list`,register:Rt}),D({name:`kick/explain`,register:za}),D({name:`kick/mcp`,register:Xa}),D({name:`kick/tinker`,register:eo}),D({name:`kick/remove`,register:oo}),D({name:`kick/typegen`,register:lo}),D({name:`kick/check`,register:So}),D({name:`kick/doctor`,register:Uo}),D({name:`kick/codemod`,register:Go}),D({name:`kick/registry`,typegens:[us()]}),D({name:`kick/services`,typegens:[ds()]}),D({name:`kick/modules`,typegens:[fs()]}),D({name:`kick/plugins`,typegens:[ps()]}),D({name:`kick/augmentations`,typegens:[ms()]}),D({name:`kick/context`,typegens:[hs()]}),D({name:`kick/assets`,typegens:[Ko()]}),D({name:`kick/routes`,typegens:[es()]}),D({name:`kick/env`,typegens:[is()]})],vs=f(b(import.meta.url)),ys=JSON.parse(a(h(vs,`..`,`package.json`),`utf-8`));async function bs(){let e=new t;e.name(`kick`).description(`KickJS — A production-grade, decorator-driven Node.js framework`).version(ys.version);let n=Gt(process.cwd()),r=n,i=await M(r)??{},a=Pe([..._s,...i.plugins??[]],i.commands??[]);await a.register(e,{cwd:r,projectRoot:n,config:i,log:e=>console.log(e)}),be(e,{...i,commands:a.commands}),e.showHelpAfterError(),await e.parseAsync(process.argv)}bs().catch(e=>{console.error(e instanceof Error?e.message:e),process.exitCode=1});export{};