@forinda/kickjs-cli 6.3.0 → 6.4.0

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 (31) hide show
  1. package/README.md +1 -1
  2. package/dist/{agent-docs-DrGK8taL.mjs → agent-docs-lDM1Nx6J.mjs} +3 -3
  3. package/dist/{agent-docs-DrGK8taL.mjs.map → agent-docs-lDM1Nx6J.mjs.map} +1 -1
  4. package/dist/{build-BP3bAsWN.mjs → build-CBRWV98i.mjs} +3 -3
  5. package/dist/{build-BP3bAsWN.mjs.map → build-CBRWV98i.mjs.map} +1 -1
  6. package/dist/{builtins-DBoirqjH.mjs → builtins-1-t8nFZe.mjs} +2 -2
  7. package/dist/cli.mjs +137 -130
  8. package/dist/{config-BCGU5sEB.mjs → config-C6Na808n.mjs} +3 -3
  9. package/dist/{config-BCGU5sEB.mjs.map → config-C6Na808n.mjs.map} +1 -1
  10. package/dist/{doctor-CyW4lHWm.mjs → doctor-DlWMC_2O.mjs} +9 -9
  11. package/dist/doctor-DlWMC_2O.mjs.map +1 -0
  12. package/dist/index.d.mts +14 -0
  13. package/dist/index.d.mts.map +1 -1
  14. package/dist/index.mjs +2 -2
  15. package/dist/{plugin-D5VBchsh.mjs → plugin-DlIRWEfP.mjs} +3 -3
  16. package/dist/{plugin-D5VBchsh.mjs.map → plugin-DlIRWEfP.mjs.map} +1 -1
  17. package/dist/{project-docs-BC9IeqGg.mjs → project-docs-Dr75Phev.mjs} +13 -13
  18. package/dist/project-docs-Dr75Phev.mjs.map +1 -0
  19. package/dist/{project-root-By_tYe1R.mjs → project-root-BKYv-vPf.mjs} +3 -3
  20. package/dist/{project-root-By_tYe1R.mjs.map → project-root-BKYv-vPf.mjs.map} +1 -1
  21. package/dist/{rolldown-runtime-CxXPTOrW.mjs → rolldown-runtime-DLwMHNw-.mjs} +1 -1
  22. package/dist/{run-plugins-DEn7gHVu.mjs → run-plugins-DaN0MHlX.mjs} +28 -21
  23. package/dist/run-plugins-DaN0MHlX.mjs.map +1 -0
  24. package/dist/{typegen-C5ZXwZZv.mjs → typegen-DJGvcWVf.mjs} +18 -18
  25. package/dist/typegen-DJGvcWVf.mjs.map +1 -0
  26. package/dist/{types-5S0Va4VP.mjs → types-CmiWgylI.mjs} +1 -1
  27. package/package.json +14 -14
  28. package/dist/doctor-CyW4lHWm.mjs.map +0 -1
  29. package/dist/project-docs-BC9IeqGg.mjs.map +0 -1
  30. package/dist/run-plugins-DEn7gHVu.mjs.map +0 -1
  31. package/dist/typegen-C5ZXwZZv.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs-cli v6.3.0
2
+ * @forinda/kickjs-cli v6.4.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{_ as e,b as t,c as n,d as r,f as i,g as a,h as o,l as s,m as c,p as l,s as u,u as d,v as f,y as p}from"./project-docs-BC9IeqGg.mjs";import{A as m,C as h,D as g,E as _,F as v,I as y,L as b,M as ee,N as x,O as S,P as C,R as w,S as te,T as ne,_ as re,a as ie,b as ae,c as oe,d as se,f as ce,g as le,h as ue,i as de,j as fe,k as pe,l as me,m as he,p as ge,r as _e,u as ve,v as ye,w as be,x as xe,y as Se}from"./doctor-CyW4lHWm.mjs";import{a as T,i as E,o as Ce,s as we}from"./config-BCGU5sEB.mjs";import{t as Te}from"./project-root-By_tYe1R.mjs";import{n as D}from"./types-5S0Va4VP.mjs";import{t as Ee}from"./build-BP3bAsWN.mjs";import{n as De}from"./agent-docs-DrGK8taL.mjs";import{n as Oe}from"./plugin-D5VBchsh.mjs";import{a as ke,c as Ae,d as je,f as Me,g as Ne,h as Pe,i as Fe,l as Ie,m as Le,o as Re,p as ze,r as Be,s as Ve,t as He,u as Ue}from"./typegen-C5ZXwZZv.mjs";import O,{basename as We,dirname as k,join as A,relative as j,resolve as M,sep as N}from"node:path";import{cpSync as Ge,existsSync as P,mkdirSync as Ke,readFileSync as F,readdirSync as qe,rmSync as Je,writeFileSync as Ye}from"node:fs";import{copyFile as Xe,mkdir as I,readFile as L,readdir as Ze,rm as Qe,stat as $e,writeFile as R}from"node:fs/promises";import{fork as et,spawn as tt,spawnSync as nt}from"node:child_process";import{fileURLToPath as rt,pathToFileURL as z}from"node:url";import{arch as it,platform as at,release as ot}from"node:os";const st=[{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 ct(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(`--runtime <engine>`,`HTTP runtime: express | fastify | h3`).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)=>{n(`KickJS — Create a new project`);let o=!!(t.yes||t.nonInteractive);e||=o?`my-api`:await c({message:`Project name`,placeholder:`my-api`,defaultValue:`my-api`});let l;if(e===`.`?(l=M(`.`),e=We(l)):l=M(t.directory||e),P(l)){let n=qe(l);if(n.length>0){if(t.force)s.warn(`Clearing existing files in ${l}`);else if(o){s.warn(`Directory "${e}" is not empty. Pass --force to clear it.`),r(`Aborted.`);return}else{s.warn(`Directory "${e}" is not empty:`);let t=n.slice(0,5);for(let e of t)s.message(` - ${e}`);if(n.length>5&&s.message(` ... and ${n.length-5} more`),!await u({message:a.red(`Remove all existing files and proceed?`),initialValue:!1})){r(`Aborted.`);return}}for(let e of n)Je(M(l,e),{recursive:!0,force:!0})}}let f=t.template;f||=o?`minimal`:await i({message:`Project template`,options:[{value:`rest`,label:`REST API`,hint:`Express + Swagger`},{value:`minimal`,label:`Minimal`,hint:`bare Express`}]});let p=t.runtime;p||=o?`express`:await i({message:`HTTP runtime`,options:[{value:`express`,label:`Express`,hint:`default, zero-config`},{value:`fastify`,label:`Fastify`,hint:`fastify + @fastify/middie`},{value:`h3`,label:`h3`,hint:`Nitro / Nuxt engine`}]});let m=t.pm;m||=o?await he(void 0):await i({message:`Package manager`,options:[{value:`pnpm`,label:`pnpm`},{value:`npm`,label:`npm`},{value:`yarn`,label:`yarn`},{value:`bun`,label:`bun`}]});let h=t.repo;h||=o?`inmemory`:await c({message:`Repository name`,placeholder:`inmemory (or a DB name, e.g. postgres)`,defaultValue:`inmemory`}),we(h);let g=t.schema;g||=o?`zod`:await i({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(g)||(s.warn(`Unknown --schema "${g}", falling back to zod.`),g=`zod`);let _;if(t.packages!==void 0){let e=t.packages.trim().toLowerCase();_=e===``||e===`none`||e===`false`?[]:t.packages.split(`,`).map(e=>e.trim()).filter(Boolean)}else _=o?[]:await d({message:`Select packages to include`,options:[...st],required:!1});let v;v=t.git===void 0?o?!0:await u({message:`Initialize git repository?`,initialValue:!0}):t.git;let y;y=t.install===void 0?o?!0:await u({message:`Install dependencies?`,initialValue:!0}):t.install,await ve({name:e,directory:l,packageManager:m,initGit:v,installDeps:y,template:f,defaultRepo:h,packages:_,schemaLib:g,runtime:p}),r(`Done! Next steps: ${a.cyan(`cd ${e} && ${m} dev`)}`)})}async function lt(e){let{name:n,outDir:r}=e,i=b(n),a=w(n),o=[],s=A(r,`${i}.plugin.ts`);return await t(s,`import {
11
+ import{_ as e,b as t,c as n,d as r,f as i,g as a,h as o,l as s,m as c,p as l,s as u,u as d,v as f,y as p}from"./project-docs-Dr75Phev.mjs";import{A as m,C as h,D as g,E as _,F as v,I as y,L as b,M as ee,N as x,O as S,P as C,R as w,S as te,T as ne,_ as re,a as ie,b as ae,c as oe,d as se,f as ce,g as le,h as ue,i as de,j as fe,k as pe,l as me,m as he,p as ge,r as _e,u as ve,v as ye,w as be,x as xe,y as Se}from"./doctor-DlWMC_2O.mjs";import{a as T,i as E,o as Ce,s as we}from"./config-C6Na808n.mjs";import{t as Te}from"./project-root-BKYv-vPf.mjs";import{n as D}from"./types-CmiWgylI.mjs";import{t as Ee}from"./build-CBRWV98i.mjs";import{n as De}from"./agent-docs-lDM1Nx6J.mjs";import{n as Oe}from"./plugin-DlIRWEfP.mjs";import{a as ke,c as Ae,d as je,f as Me,g as Ne,h as Pe,i as Fe,l as Ie,m as Le,o as Re,p as ze,r as Be,s as Ve,t as He,u as Ue}from"./typegen-DJGvcWVf.mjs";import O,{basename as We,dirname as k,join as A,relative as j,resolve as M,sep as N}from"node:path";import{cpSync as Ge,existsSync as P,mkdirSync as Ke,readFileSync as F,readdirSync as qe,rmSync as Je,writeFileSync as Ye}from"node:fs";import{copyFile as Xe,mkdir as I,readFile as L,readdir as Ze,rm as Qe,stat as $e,writeFile as R}from"node:fs/promises";import{fork as et,spawn as tt,spawnSync as nt}from"node:child_process";import{fileURLToPath as rt,pathToFileURL as z}from"node:url";import{arch as it,platform as at,release as ot}from"node:os";const st=[{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 ct(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(`--runtime <engine>`,`HTTP runtime: express | fastify | h3`).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)=>{n(`KickJS — Create a new project`);let o=!!(t.yes||t.nonInteractive);e||=o?`my-api`:await c({message:`Project name`,placeholder:`my-api`,defaultValue:`my-api`});let l;if(e===`.`?(l=M(`.`),e=We(l)):l=M(t.directory||e),P(l)){let n=qe(l);if(n.length>0){if(t.force)s.warn(`Clearing existing files in ${l}`);else if(o){s.warn(`Directory "${e}" is not empty. Pass --force to clear it.`),r(`Aborted.`);return}else{s.warn(`Directory "${e}" is not empty:`);let t=n.slice(0,5);for(let e of t)s.message(` - ${e}`);if(n.length>5&&s.message(` ... and ${n.length-5} more`),!await u({message:a.red(`Remove all existing files and proceed?`),initialValue:!1})){r(`Aborted.`);return}}for(let e of n)Je(M(l,e),{recursive:!0,force:!0})}}let f=t.template;f||=o?`minimal`:await i({message:`Project template`,options:[{value:`rest`,label:`REST API`,hint:`Express + Swagger`},{value:`minimal`,label:`Minimal`,hint:`bare Express`}]});let p=t.runtime;p||=o?`express`:await i({message:`HTTP runtime`,options:[{value:`express`,label:`Express`,hint:`default, zero-config`},{value:`fastify`,label:`Fastify`,hint:`fastify + @fastify/middie`},{value:`h3`,label:`h3`,hint:`Nitro / Nuxt engine`}]});let m=t.pm;m||=o?await he(void 0):await i({message:`Package manager`,options:[{value:`pnpm`,label:`pnpm`},{value:`npm`,label:`npm`},{value:`yarn`,label:`yarn`},{value:`bun`,label:`bun`}]});let h=t.repo;h||=o?`inmemory`:await c({message:`Repository name`,placeholder:`inmemory (or a DB name, e.g. postgres)`,defaultValue:`inmemory`}),we(h);let g=t.schema;g||=o?`zod`:await i({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(g)||(s.warn(`Unknown --schema "${g}", falling back to zod.`),g=`zod`);let _;if(t.packages!==void 0){let e=t.packages.trim().toLowerCase();_=e===``||e===`none`||e===`false`?[]:t.packages.split(`,`).map(e=>e.trim()).filter(Boolean)}else _=o?[]:await d({message:`Select packages to include`,options:[...st],required:!1});let v;v=t.git===void 0?o?!0:await u({message:`Initialize git repository?`,initialValue:!0}):t.git;let y;y=t.install===void 0?o?!0:await u({message:`Install dependencies?`,initialValue:!0}):t.install,await ve({name:e,directory:l,packageManager:m,initGit:v,installDeps:y,template:f,defaultRepo:h,packages:_,schemaLib:g,runtime:p}),r(`Done! Next steps: ${a.cyan(`cd ${e} && ${m} dev`)}`)})}async function lt(e){let{name:n,outDir:r}=e,i=b(n),a=w(n),o=[],s=A(r,`${i}.plugin.ts`);return await t(s,`import {
12
12
  definePlugin,
13
13
  type AppAdapter,
14
14
  type AppModuleEntry,
@@ -116,7 +116,7 @@ export const ${a}Plugin = definePlugin<${a}PluginConfig>({
116
116
  * Return Context Contributors to merge into every route's pipeline.
117
117
  * Plugins contribute at the same \`'adapter'\` precedence level as
118
118
  * adapters — overrideable per-route at the method / class / module
119
- * level. See https://forinda.github.io/kick-js/guide/context-decorators
119
+ * level. See https://kickjs.app/guide/context-decorators
120
120
  *
121
121
  * Delete this hook if your plugin doesn't ship typed per-request values.
122
122
  */
@@ -231,7 +231,7 @@ export default defineConfig({
231
231
  ],
232
232
  })
233
233
  `),[n])}function B(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 V(e,t){let n=t.exec(e);if(!n)return null;let r=n.index+n[0].length-1,i=B(e,r);return i===-1?null:e.slice(r+1,i)}function H(e,t,n){let r=` `.repeat(n);return e.split(`
234
- `).map(e=>{if(e.trim()===``)return e;let n=RegExp(`^ {0,${t}}`);return r+e.replace(n,``)}).join(`
234
+ `).map(e=>{if(e.trim()===``)return e;let n=RegExp(`^ {0,${t}}`),i=e.replace(n,``);return r+i}).join(`
235
235
  `)}function mt(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 ht(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 gt(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=B(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=V(o,/register\s*\(([^)]*)\)\s*:\s*void\s*\{/),u=V(o,/contributors\s*\(\s*\)\s*:\s*ContributorRegistrations\s*\{/),d=V(o,/routes\s*\(\s*\)\s*:\s*[A-Za-z|[\]\s]+\{/);if(!d)return{migrated:null,reason:`routes() method missing or signature unrecognized`};let f=mt(s),p=``;return l&&(p+=` register(container) {${H(l,4,6)} },\n\n`),u&&(p+=` contributors() {${H(u,4,6)} },\n\n`),p+=` routes() {${H(d,4,6)} },`,{migrated:`${f}${`export const ${r} = defineModule({
236
236
  name: '${r}',
237
237
  build: () => ({
@@ -377,7 +377,7 @@ import { modules } from './modules'
377
377
  import './config' // ← add this — registers env schema
378
378
  import { bootstrap } from '@forinda/kickjs'
379
379
  import { modules } from './modules'
380
- `,docs:`https://forinda.github.io/kick-js/guide/configuration.html#wiring-the-schema-at-startup`}}}},{match(e,t){let n=X(e,[`vitest`,`test`,`spec`,`__tests__`,`.test.`]);return X(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.
380
+ `,docs:`https://kickjs.app/guide/configuration.html#wiring-the-schema-at-startup`}}}},{match(e,t){let n=X(e,[`vitest`,`test`,`spec`,`__tests__`,`.test.`]);return X(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.
381
381
  When vitest re-imports your modules across tests, the same class can be
382
382
  registered twice and the container throws. The fix is to wipe the
383
383
  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'
@@ -387,7 +387,7 @@ describe('UserController', () => {
387
387
  beforeEach(() => Container.reset())
388
388
 
389
389
  it('does the thing', async () => { /* ... */ })
390
- })`,docs:`https://forinda.github.io/kick-js/guide/testing.html`}}:null}},{match(e,t){return e.includes(`@Module`)||fn(e,[`Module`,`is not a function`])||fn(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
390
+ })`,docs:`https://kickjs.app/guide/testing.html`}}:null}},{match(e,t){return e.includes(`@Module`)||fn(e,[`Module`,`is not a function`])||fn(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
391
391
  pattern instead: a class implements AppModule and exposes routes() that
392
392
  returns the controller wiring. This was a deliberate choice — modules
393
393
  become explicit values rather than metadata, which makes them easier to
@@ -408,13 +408,13 @@ export class UserModule implements AppModule {
408
408
  controller: UserController,
409
409
  }
410
410
  }
411
- }`,docs:`https://forinda.github.io/kick-js/guide/project-structure.html`}}:null}},{match(e,t){return/KickRoutes\s*\[\s*['"](GET|POST|PUT|PATCH|DELETE)/i.test(e)?{confidence:95,diagnosis:{id:`legacy-kick-routes-bracket-syntax`,title:`KickRoutes['POST /users'] is the legacy v1 syntax`,explanation:`KickJS v2 changed the typegen output from a flat string-keyed map to a
411
+ }`,docs:`https://kickjs.app/guide/project-structure.html`}}:null}},{match(e,t){return/KickRoutes\s*\[\s*['"](GET|POST|PUT|PATCH|DELETE)/i.test(e)?{confidence:95,diagnosis:{id:`legacy-kick-routes-bracket-syntax`,title:`KickRoutes['POST /users'] is the legacy v1 syntax`,explanation:`KickJS v2 changed the typegen output from a flat string-keyed map to a
412
412
  namespaced shape: KickRoutes.UserController["create"] instead of
413
413
  KickRoutes["POST /users"]. The new form is per-controller, per-method,
414
414
  and matches the actual class names so refactors propagate via
415
415
  rename-symbol instead of grep.`,fix:`Update the Ctx<...> type parameter to use the namespace form:`,codeBefore:`@Post('/', { body: createUserSchema })
416
416
  create(ctx: Ctx<KickRoutes['POST /users']>) { /* ... */ }`,codeAfter:`@Post('/', { body: createUserSchema, name: 'CreateUser' })
417
- create(ctx: Ctx<KickRoutes.UserController['create']>) { /* ... */ }`,docs:`https://forinda.github.io/kick-js/guide/typegen.html`}}:null}},{match(e,t){let n=X(e,[`cluster`,`workers`,`two ports`,`duplicate server`]),r=X(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
417
+ create(ctx: Ctx<KickRoutes.UserController['create']>) { /* ... */ }`,docs:`https://kickjs.app/guide/typegen.html`}}:null}},{match(e,t){let n=X(e,[`cluster`,`workers`,`two ports`,`duplicate server`]),r=X(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
418
418
  cluster: { workers: N }, the framework forks N workers, each of which
419
419
  spins up its own Vite instance on a separate port. The fix landed in
420
420
  v2.2.5: McpAdapter (and bootstrap()) now detects Vite dev mode and
@@ -422,7 +422,7 @@ silently skips cluster, with a warning. If you see this on an older
422
422
  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({
423
423
  modules,
424
424
  cluster: process.env.NODE_ENV === 'production' ? { workers: 4 } : false,
425
- })`,docs:`https://forinda.github.io/kick-js/guide/cluster.html`}}}},{match(e,t){return X(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
425
+ })`,docs:`https://kickjs.app/guide/cluster.html`}}}},{match(e,t){return X(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
426
426
  reflect-metadata polyfill. The polyfill must be imported once,
427
427
  before any decorator runs. Most projects do this at the top of
428
428
  src/index.ts; missing the import causes obscure "design:paramtypes"
@@ -431,7 +431,7 @@ import './config'
431
431
  import { bootstrap } from '@forinda/kickjs'
432
432
  import { modules } from './modules'
433
433
 
434
- export const app = await bootstrap({ modules })`,docs:`https://forinda.github.io/kick-js/guide/dependency-injection.html`}}:null}},{match(e,t){return X(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
434
+ export const app = await bootstrap({ modules })`,docs:`https://kickjs.app/guide/dependency-injection.html`}}:null}},{match(e,t){return X(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
435
435
  generated a module via \`kick g module foo\` but the routes don't appear,
436
436
  the most likely cause is that the module is missing from the exported
437
437
  array. The CLI usually wires this automatically, but a hand-edit can
@@ -439,14 +439,14 @@ drop the entry.`,fix:`Open src/modules/index.ts and verify the module is in the
439
439
  import { UserModule } from './users/user.module'
440
440
  import { TaskModule } from './tasks/task.module' // ← was this missing?
441
441
 
442
- export const modules: AppModuleEntry[] = [UserModule(), TaskModule()]`,docs:`https://forinda.github.io/kick-js/guide/project-structure.html`}}:null}}];function mn(e,t){let n=null;for(let r of pn){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 hn(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.
442
+ export const modules: AppModuleEntry[] = [UserModule(), TaskModule()]`,docs:`https://kickjs.app/guide/project-structure.html`}}:null}}];function mn(e,t){let n=null;for(let r of pn){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 hn(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.
443
443
  export OPENAI_API_KEY="sk-..."
444
444
 
445
445
  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:
446
446
  kick add ai
447
447
 
448
448
  Or manually:
449
- pnpm add @forinda/kickjs-ai`}}let{OpenAIProvider:i}=r,a=new i({apiKey:n,defaultChatModel:e.model??`gpt-4o-mini`}),o=gn(e.cwd),s=`Error or stack trace:\n\n${e.input.trim()}`;try{let e=_n((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 gn(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(`
449
+ pnpm add @forinda/kickjs-ai`}}let{OpenAIProvider:i}=r,a=new i({apiKey:n,defaultChatModel:e.model??`gpt-4o-mini`}),o=gn(e.cwd),s=`Error or stack trace:\n\n${e.input.trim()}`;try{let e=_n((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 gn(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://kickjs.app/ — prefer`,`that domain for any doc links you suggest.`,e?`The project is located at ${e}.`:``].filter(e=>e.length>0).join(`
450
450
  `)}function _n(e){let t=[e,vn(e),yn(e)].filter(e=>e!==null);for(let e of t)try{let t=JSON.parse(e);if(bn(t))return t}catch{continue}return null}function vn(e){let t=e.match(/```(?:json)?\s*\n([\s\S]*?)```/);return t?t[1]?.trim()??null:null}function yn(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 bn(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 xn(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 wn(e,t.message);(!n||n.trim().length===0)&&(process.stderr.write(`Error: no input provided.
451
451
 
452
452
  Pass a message as a positional arg, --message flag, or pipe via stdin:
@@ -464,7 +464,7 @@ Pass a message as a positional arg, --message flag, or pipe via stdin:
464
464
  `):process.stdout.write(` No known-issue matched. Things you can try:
465
465
 
466
466
  1. Check the framework docs for the error keywords:
467
- https://forinda.github.io/kick-js/
467
+ https://kickjs.app/
468
468
 
469
469
  2. Re-run with --ai to fall back to an LLM (requires
470
470
  @forinda/kickjs-ai with a configured provider):
@@ -538,7 +538,7 @@ server.on('exit', () => {
538
538
  Cancelled.
539
539
  `);return}await Qe(l,{recursive:!0,force:!0}),console.log(` Deleted: ${l}`);let d=A(n,`index.ts`);if(await f(d)){let e=await L(d,`utf-8`),t=e,n=RegExp(`^import\\s*\\{\\s*${x(s)}Module\\s*\\}\\s*from\\s*['"][^'"]*${x(c)}(?:/[^'"]*)?['"].*\\n?`,`gm`);e=e.replace(n,``),e=Rn(e,s),e=e.replace(/\n{3,}/g,`
540
540
 
541
- `),e!==t&&(await R(d,e,`utf-8`),console.log(` Unregistered: ${s}Module from ${d}`))}console.log(`\n Module '${c}' removed.\n`)}function Bn(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=T(await E(process.cwd())),r=t.modulesDir??n.dir??`src/modules`,i=t.pluralize===!1?!1:n.pluralize??!0;for(let n of e)await zn({name:n,modulesDir:M(r),force:t.force,pluralize:i})})}function Vn(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 Hn(e){if(e!==void 0)return e===`false`||e===`off`||e===`none`?!1:e}function Un(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(`--fix`,`Patch module import.meta.glob() calls to cover decorated classes that aren't loaded by any glob (orphans)`).option(`--list`,"List every registered typegen plugin id (use to populate `typegen.disable`)").option(`--no-cache`,`Disable the persistent scan cache; re-read + re-extract every file from cold`).action(async e=>{let t=Te(process.cwd()),n=await E(t);if(e.list){let{mergeCliPlugins:e}=await import(`./plugin-D5VBchsh.mjs`).then(e=>e.t),{builtinCliPlugins:t}=await import(`./builtins-DBoirqjH.mjs`),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(`
541
+ `),e!==t&&(await R(d,e,`utf-8`),console.log(` Unregistered: ${s}Module from ${d}`))}console.log(`\n Module '${c}' removed.\n`)}function Bn(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=T(await E(process.cwd())),r=t.modulesDir??n.dir??`src/modules`,i=t.pluralize===!1?!1:n.pluralize??!0;for(let n of e)await zn({name:n,modulesDir:M(r),force:t.force,pluralize:i})})}function Vn(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 Hn(e){if(e!==void 0)return e===`false`||e===`off`||e===`none`?!1:e}function Un(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(`--fix`,`Patch module import.meta.glob() calls to cover decorated classes that aren't loaded by any glob (orphans)`).option(`--list`,"List every registered typegen plugin id (use to populate `typegen.disable`)").option(`--no-cache`,`Disable the persistent scan cache; re-read + re-extract every file from cold`).action(async e=>{let t=Te(process.cwd()),n=await E(t);if(e.list){let{mergeCliPlugins:e}=await import(`./plugin-DlIRWEfP.mjs`).then(e=>e.t),{builtinCliPlugins:t}=await import(`./builtins-1-t8nFZe.mjs`),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(`
542
542
  Registered typegen plugins:
543
543
  `);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=Vn(e.schemaValidator)??n?.typegen?.schemaValidator??`zod`,i=Hn(e.envFile)??n?.typegen?.envFile,a={cwd:t,srcDir:e.src??n?.typegen?.srcDir,outDir:e.out??n?.typegen?.outDir,silent:e.silent,fix:e.fix,allowDuplicates:e.allowDuplicates,noCache:e.cache===!1,schemaValidator:r,envFile:i,assetMap:n?.assetMap,runPlugins:!1};try{if(e.watch){let t=await Be(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 He(a);let r=await Gt({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 Fe(M(t,e.out??n?.typegen?.outDir??`.kickjs/types`),r,e.silent??!1)}}catch(e){e instanceof Ve?console.error(`
544
544
  `+e.message+`
@@ -556,22 +556,29 @@ server.on('exit', () => {
556
556
  The regex-based rewrite handles the shapes our templates produce.
557
557
  Hand-rolled modules with non-standard structures may be skipped.
558
558
  Always commit before running with --apply.
559
- `),process.exit(1));let r=T(await E(process.cwd())),i=M(e.modulesDir??r.dir??`src/modules`),o;e.target===`define`||e.target===`class`?o=e.target:e.target===void 0?o=r.style??`define`:(console.error(`\n ${a.red(`Error:`)} --target must be 'define' or 'class' (got '${e.target}').\n`),process.exit(1));let s=a.dim(`→ ${o}`),c=n?a.dim(`(dry-run)`):a.bold(`(applying)`);console.log(`\n ${a.bold(`kick codemod modules`)} ${s} ${c}`),console.log(` modulesDir: ${a.dim(i)}\n`);let l=e.backup!==!1&&!n,u=await Ct(i,{dryRun:n,target:o,backup:l});if(u.backupDir){let e=u.backupDir;console.log(` ${a.green(`✓`)} backup: ${a.dim(e)}\n ${a.dim(`(restore: rm -rf <modulesDir> && mv "<backup>" <modulesDir>)`)}\n`)}else !n&&e.backup===!1&&console.log(` ${a.dim(`(--no-backup — skipping snapshot)`)}\n`);let d=0,f=0;for(let e of u.files)if(e.status===`migrated`)d++,console.log(` ${a.green(`✓`)} ${e.path}`);else{f++;let t=a.dim(`(${e.reason??`skipped`})`);console.log(` ${a.dim(`-`)} ${e.path} ${t}`)}if(console.log(),u.indexStatus===`migrated`)console.log(` ${a.green(`✓`)} ${u.indexPath}`);else if(u.indexStatus===`skipped`){let e=a.dim(`(${u.indexReason??`skipped`})`);console.log(` ${a.dim(`-`)} ${u.indexPath} ${e}`)}else console.log(` ${a.dim(`-`)} ${u.indexPath} ${a.dim(`(not found)`)}`);let m=n?a.dim(` (dry-run — pass --apply to write)`):``;console.log(`\n ${a.bold(String(d))} migrated, ${a.bold(String(f))} skipped${m}\n`)})}const ir=()=>({id:`kick/assets`,inputs:[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`],async generate(e){if(!P(O.resolve(e.cwd,`kick.config.ts`)))return null;let t=await E(e.cwd);if(!t?.assetMap)return null;let n=ke(t.assetMap,e.cwd);return n.count===0?null:Re(n)}}),ar="/* 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 or(e,t,n,r={}){if(e.length===0)return`${ar}
559
+ `),process.exit(1));let r=T(await E(process.cwd())),i=M(e.modulesDir??r.dir??`src/modules`),o;e.target===`define`||e.target===`class`?o=e.target:e.target===void 0?o=r.style??`define`:(console.error(`\n ${a.red(`Error:`)} --target must be 'define' or 'class' (got '${e.target}').\n`),process.exit(1));let s=a.dim(`→ ${o}`),c=n?a.dim(`(dry-run)`):a.bold(`(applying)`);console.log(`\n ${a.bold(`kick codemod modules`)} ${s} ${c}`),console.log(` modulesDir: ${a.dim(i)}\n`);let l=e.backup!==!1&&!n,u=await Ct(i,{dryRun:n,target:o,backup:l});if(u.backupDir){let e=u.backupDir;console.log(` ${a.green(`✓`)} backup: ${a.dim(e)}\n ${a.dim(`(restore: rm -rf <modulesDir> && mv "<backup>" <modulesDir>)`)}\n`)}else!n&&e.backup===!1&&console.log(` ${a.dim(`(--no-backup — skipping snapshot)`)}\n`);let d=0,f=0;for(let e of u.files)if(e.status===`migrated`)d++,console.log(` ${a.green(`✓`)} ${e.path}`);else{f++;let t=a.dim(`(${e.reason??`skipped`})`);console.log(` ${a.dim(`-`)} ${e.path} ${t}`)}if(console.log(),u.indexStatus===`migrated`)console.log(` ${a.green(`✓`)} ${u.indexPath}`);else if(u.indexStatus===`skipped`){let e=a.dim(`(${u.indexReason??`skipped`})`);console.log(` ${a.dim(`-`)} ${u.indexPath} ${e}`)}else console.log(` ${a.dim(`-`)} ${u.indexPath} ${a.dim(`(not found)`)}`);let m=n?a.dim(` (dry-run — pass --apply to write)`):``;console.log(`\n ${a.bold(String(d))} migrated, ${a.bold(String(f))} skipped${m}\n`)})}const ir=()=>({id:`kick/assets`,inputs:[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`],async generate(e){if(!P(O.resolve(e.cwd,`kick.config.ts`)))return null;let t=await E(e.cwd);if(!t?.assetMap)return null;let n=ke(t.assetMap,e.cwd);return n.count===0?null:Re(n)}}),ar="/* 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 or(e,t,n,r={}){if(e.length===0)return`${ar}
560
560
  // (no routes discovered yet — annotate a controller method with
561
561
  // @Get/@Post/@Put/@Delete/@Patch and re-run \`kick typegen\`)
562
562
  declare global {
563
563
  // eslint-disable-next-line @typescript-eslint/no-namespace
564
- namespace KickRoutes {}
564
+ namespace KickRoutes {
565
+ // Always present so \`createClient<KickRoutes.Api>\` compiles before the
566
+ // first route exists (fresh project / pre-controller typegen runs).
567
+ interface Api {}
568
+ }
565
569
  }
566
570
 
567
571
  export {}
568
- `;let i=new Map;for(let t of e){let e=i.get(t.controller)??[];e.push(t),i.set(t.controller,e)}let a=new Map,o=(e,i,o)=>{let s=lr(e,i.filePath,t,n,a);if(!s){if(e&&n!==!1){let t=o===`params`?`URL-pattern params`:o===`query`&&i.queryFilterable!==null?`the @ApiQueryParams-derived query shape`:`'unknown'`;r.onWarn?.(`route ${i.controller}.${i.method} (${i.httpMethod} ${i.path}): ${o} schema '${e.identifier}' could not be statically resolved — falling back to ${t}. Export the schema from the controller file or import it with a static specifier.`)}return null}return n===`kickjs-schema`?`import('@forinda/kickjs-schema').InferSchemaOutput<typeof ${s}>`:`import('zod').infer<typeof ${s}>`},s=[];for(let[e,t]of i){let n=[` interface ${e} {`];for(let e of t){let t=e.pathParams.length>0?`{ ${e.pathParams.map(e=>`${e}: string`).join(`; `)} }`:`{}`,r=o(e.bodySchema,e,`body`),i=o(e.querySchema,e,`query`),a=o(e.paramsSchema,e,`params`)??t,s=r??`unknown`,c=i??sr(e),l=cr(e);n.push(` /**`,` * ${e.httpMethod} ${e.path}`,...l.map(e=>` * ${e}`),` */`,` ${e.method}: {`,` params: ${a}`,` body: ${s}`,` query: ${c}`,` response: unknown`,` }`)}n.push(` }`),s.push(n.join(`
569
- `))}return`${ar}${ur(a)}
572
+ `;let i=new Map;for(let t of e){let e=i.get(t.controller)??[];e.push(t),i.set(t.controller,e)}let a=new Map,o=new Map,s=e=>{let t=`${e.filePath}::${e.controller}`,n=o.get(t);return n||(n=`_C${o.size}`,o.set(t,n)),n},c=(e,i,o)=>{let s=lr(e,i.filePath,t,n,a);if(!s){if(e&&n!==!1){let t=o===`params`?`URL-pattern params`:o===`query`&&i.queryFilterable!==null?`the @ApiQueryParams-derived query shape`:`'unknown'`;r.onWarn?.(`route ${i.controller}.${i.method} (${i.httpMethod} ${i.path}): ${o} schema '${e.identifier}' could not be statically resolved — falling back to ${t}. Export the schema from the controller file or import it with a static specifier.`)}return null}return n===`kickjs-schema`?`import('@forinda/kickjs-schema').InferSchemaOutput<typeof ${s}>`:`import('zod').infer<typeof ${s}>`},l=[];for(let[e,t]of i){let n=[` interface ${e} {`];for(let e of t){let t=e.pathParams.length>0?`{ ${e.pathParams.map(e=>`${e}: string`).join(`; `)} }`:`{}`,r=c(e.bodySchema,e,`body`),i=c(e.querySchema,e,`query`),a=c(e.paramsSchema,e,`params`)??t,o=r??`unknown`,l=i??sr(e),u=`import('@forinda/kickjs').InferHandlerResponse<${s(e)}['${e.method}']>`,d=cr(e);n.push(` /**`,` * ${e.httpMethod} ${e.path}`,...d.map(e=>` * ${e}`),` */`,` ${e.method}: {`,` params: ${a}`,` body: ${o}`,` query: ${l}`,` response: ${u}`,` }`)}n.push(` }`),l.push(n.join(`
573
+ `))}let u=[],d=new Set;i.has(`Api`)&&r.onWarn?.(`controller class 'Api' collides with the reserved KickRoutes.Api client map — its interface declaration-merges into the flat route map. Rename the controller.`);for(let[e,t]of i)for(let n of t){let t=`${n.httpMethod} ${n.mountedPath??n.path}`;if(d.has(t)){r.onWarn?.(`duplicate route '${t}' (${e}.${n.method}) — two handlers claim the same verb+path at runtime. KickRoutes.Api keeps the first (scan order, which may not match runtime dispatch); resolve the conflict in the modules.`);continue}d.add(t),u.push(` '${t}': ${e}['${n.method}']`)}let f=[` interface Api {`,...u,` }`].join(`
574
+ `);l.push(f);let p=[],m=new Map;for(let t of e)m.set(`${t.filePath}::${t.controller}`,t);for(let[e,n]of o){let r=m.get(e),i=dr(``,r.filePath,t),a=r.controllerIsDefaultExport?`default as ${n}`:`${r.controller} as ${n}`;p.push(`import type { ${a} } from '${i}'`)}let h=p.length>0?p.join(`
575
+ `)+`
576
+ `:``,g=ur(a)+h,_=l.join(`
577
+ `);return`${ar}${g}
570
578
  declare global {
571
579
  // eslint-disable-next-line @typescript-eslint/no-namespace
572
580
  namespace KickRoutes {
573
- ${s.join(`
574
- `)}
581
+ ${_}
575
582
  }
576
583
  }
577
584
 
@@ -618,4 +625,4 @@ declare global {
618
625
  export {}
619
626
  `}const gr=()=>({id:`kick/env`,outExtension:`.ts`,inputs:[`src/env.ts`,`src/**/env.ts`,`src/**/*.env.ts`],async generate(e){let t=vr(e);if(t===!1)return null;let n=await e.getScanResult({root:_r(e),cwd:e.cwd,envFile:t});if(!n.env)return null;let r=e.config?.typegen?.schemaValidator??`zod`,i=O.resolve(e.cwd,`.kickjs/types/kick__env.ts`);return hr(n.env,i,r)}});function _r(e){return O.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function vr(e){return e.config?.typegen?.envFile}function yr(e){return O.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function br(e){let t=e.config?.typegen?.envFile;if(t!==!1)return t}function $(e){return{root:yr(e),cwd:e.cwd,envFile:br(e)}}const xr=()=>({id:`kick/registry`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult($(e)),n=O.resolve(e.cwd,`.kickjs/types/kick__registry.d.ts`),r=new Set(t.collisions.map(e=>e.className));return ze(t.classes,n,r)}}),Sr=()=>({id:`kick/services`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult($(e)),n=new Set(t.collisions.map(e=>e.className));return Le(`ServiceToken`,Ie(t.classes,t.tokens,t.injects,n),"(no tokens discovered — declare with createToken<T>() or `kick g service <name>`)")}}),Cr=()=>({id:`kick/modules`,inputs:[`src/**/*.ts`],async generate(e){return Le(`ModuleToken`,Ae((await e.getScanResult($(e))).classes),"(no @Module classes discovered — `kick g module <name>` to add one)")}}),wr=()=>({id:`kick/plugins`,inputs:[`src/**/*.ts`],async generate(e){return Me((await e.getScanResult($(e))).pluginsAndAdapters)}}),Tr=()=>({id:`kick/augmentations`,inputs:[`src/**/*.ts`],async generate(e){return Ue((await e.getScanResult($(e))).augmentations)}}),Er=()=>({id:`kick/context`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult($(e));return t.contextKeys.length===0?null:je(t.contextKeys)}}),Dr={fastify:{subpath:`@forinda/kickjs/fastify`,typeName:`FastifyRuntimeTypes`},h3:{subpath:`@forinda/kickjs/h3`,typeName:`H3RuntimeTypes`}},Or=[D({name:`kick/init`,register:ct}),D({name:`kick/generate`,register:Rt}),D({name:`kick/run`,register:Zt}),D({name:`kick/info`,register:nn}),D({name:`kick/inspect`,register:dn}),D({name:`kick/add`,register:ce}),D({name:`kick/list`,register:ge}),D({name:`kick/explain`,register:xn}),D({name:`kick/mcp`,register:An}),D({name:`kick/tinker`,register:Pn}),D({name:`kick/remove`,register:Bn}),D({name:`kick/typegen`,register:Un}),D({name:`kick/check`,register:tr}),D({name:`kick/doctor`,register:_e}),D({name:`kick/codemod`,register:rr}),D({name:`kick/registry`,typegens:[xr()]}),D({name:`kick/services`,typegens:[Sr()]}),D({name:`kick/modules`,typegens:[Cr()]}),D({name:`kick/plugins`,typegens:[wr()]}),D({name:`kick/augmentations`,typegens:[Tr()]}),D({name:`kick/context`,typegens:[Er()]}),D({name:`kick/assets`,typegens:[ir()]}),D({name:`kick/routes`,typegens:[fr()]}),D({name:`kick/env`,typegens:[gr()]}),D({name:`kick/runtime`,typegens:[{id:`kick/runtime`,outExtension:`.ts`,inputs:[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`,`kick.config.json`],async generate(e){let t=e.config?.runtime;if(t!==`fastify`&&t!==`h3`)return null;let{subpath:n,typeName:r}=Dr[t];return[`// Runtime escape-hatch types for the '${t}' engine (kick.config runtime).`,`declare module '@forinda/kickjs' {`,` interface KickRuntimeRegister {`,` runtime: import('${n}').${r}`,` }`,`}`,``,`export {}`,``].join(`
620
627
  `)}}]})];export{Ut as applyDisableFilter,Gt as runAllPluginTypegens,Or as t};
621
- //# sourceMappingURL=run-plugins-DEn7gHVu.mjs.map
628
+ //# sourceMappingURL=run-plugins-DaN0MHlX.mjs.map