@forinda/kickjs-cli 8.1.5 → 8.1.6

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 (41) hide show
  1. package/dist/{agent-docs-BK33p0Pw.mjs → agent-docs-BBlVl1tY.mjs} +2 -2
  2. package/dist/{agent-docs-DzaWoZc7.mjs → agent-docs-CW5TQHti.mjs} +3 -3
  3. package/dist/{agent-docs-DzaWoZc7.mjs.map → agent-docs-CW5TQHti.mjs.map} +1 -1
  4. package/dist/{build-DBT23vXN.mjs → build-DOI_zYDS.mjs} +3 -3
  5. package/dist/{build-DBT23vXN.mjs.map → build-DOI_zYDS.mjs.map} +1 -1
  6. package/dist/{build-clh7HpZV.mjs → build-htBdOg51.mjs} +2 -2
  7. package/dist/{builtins-HdwKAx0s.mjs → builtins-Cj4BWpIe.mjs} +2 -2
  8. package/dist/{builtins-B6Dc2coA.mjs → builtins-SMK1mtlk.mjs} +104 -8
  9. package/dist/cli.mjs +2 -2
  10. package/dist/{config-CzL24fBQ.mjs → config-BYSNxf_t.mjs} +2 -2
  11. package/dist/{config-D06pHD-Y.mjs → config-DST3ilXt.mjs} +3 -3
  12. package/dist/{config-D06pHD-Y.mjs.map → config-DST3ilXt.mjs.map} +1 -1
  13. package/dist/{doctor-Bi_jVzha.mjs → doctor-CJYTXARe.mjs} +4 -4
  14. package/dist/{doctor-Bi_jVzha.mjs.map → doctor-CJYTXARe.mjs.map} +1 -1
  15. package/dist/{fullstack-DAEEITND.mjs → fullstack-19gafr4U.mjs} +3 -3
  16. package/dist/{fullstack-CdAbknb3.mjs → fullstack-Mkw3lkF1.mjs} +4 -4
  17. package/dist/{fullstack-CdAbknb3.mjs.map → fullstack-Mkw3lkF1.mjs.map} +1 -1
  18. package/dist/index.mjs +2 -2
  19. package/dist/{plugin-CD9WjquV.mjs → plugin-Cfiz2G3K.mjs} +3 -3
  20. package/dist/{plugin-CD9WjquV.mjs.map → plugin-Cfiz2G3K.mjs.map} +1 -1
  21. package/dist/{plugin-BSNGbECd.mjs → plugin-IEDGa0ny.mjs} +2 -2
  22. package/dist/{project-DfBzpCeE.mjs → project-5ljMCm0U.mjs} +4 -4
  23. package/dist/{project-indmSdfC.mjs → project-CAamSqrL.mjs} +5 -5
  24. package/dist/{project-indmSdfC.mjs.map → project-CAamSqrL.mjs.map} +1 -1
  25. package/dist/{project-docs-DRLN1EDX.mjs → project-docs-CYCi7cHt.mjs} +1 -1
  26. package/dist/{project-docs-BCwWphge.mjs → project-docs-at2gZlUE.mjs} +2 -2
  27. package/dist/{project-docs-BCwWphge.mjs.map → project-docs-at2gZlUE.mjs.map} +1 -1
  28. package/dist/{project-root-BsyQhlS5.mjs → project-root-BhBKSGeK.mjs} +2 -2
  29. package/dist/{project-root-CQCNCAvv.mjs → project-root-PMRCA_2T.mjs} +3 -3
  30. package/dist/{project-root-CQCNCAvv.mjs.map → project-root-PMRCA_2T.mjs.map} +1 -1
  31. package/dist/{prompts-Ba0PO3Rn.mjs → prompts-BxPTyuY3.mjs} +2 -2
  32. package/dist/{prompts-Ba0PO3Rn.mjs.map → prompts-BxPTyuY3.mjs.map} +1 -1
  33. package/dist/{rolldown-runtime-DmTqmRjS.mjs → rolldown-runtime-D-i_dFAb.mjs} +1 -1
  34. package/dist/{run-plugins-BKWupYoJ.mjs → run-plugins-GxEtP9WR.mjs} +160 -64
  35. package/dist/run-plugins-GxEtP9WR.mjs.map +1 -0
  36. package/dist/{typegen-CnsfSSpH.mjs → typegen-CJvd5MEz.mjs} +5 -5
  37. package/dist/{typegen-CnsfSSpH.mjs.map → typegen-CJvd5MEz.mjs.map} +1 -1
  38. package/dist/{typegen-B6vIx4Qd.mjs → typegen-D7aeVM0D.mjs} +4 -4
  39. package/dist/{types-B6yNws8R.mjs → types-PxKCj-JF.mjs} +1 -1
  40. package/package.json +1 -1
  41. package/dist/run-plugins-BKWupYoJ.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs-cli v8.1.5
2
+ * @forinda/kickjs-cli v8.1.6
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,4 +8,4 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{t as e}from"./rolldown-runtime-DmTqmRjS.mjs";import{a as t}from"./config-CzL24fBQ.mjs";import{a as n,i as r,l as i,n as a,r as o,t as s}from"./project-docs-DRLN1EDX.mjs";import{existsSync as c,readFileSync as l}from"node:fs";import{join as u}from"node:path";import*as d from"@clack/prompts";import f from"picocolors";const p={GET:f.green,POST:f.cyan,PUT:f.yellow,PATCH:f.magenta,DELETE:f.red};function m(e){return(p[e]??f.dim)(e.padEnd(7))}function h(e){let t=`[${e}]`.padEnd(10);switch(e){case`CRITICAL`:return f.red(t);case`WARNING`:return f.yellow(t);case`INFO`:return f.blue(f.dim(t));default:return t}}f.green(`✓`),f.red(`✖`),f.yellow(`⚠`),f.blue(`ℹ`);function g(e){d.intro(f.bgCyan(f.black(` ${e} `)))}function _(e){d.outro(e)}function v(e){d.isCancel(e)&&(d.cancel(`Operation cancelled.`),process.exit(0))}async function y(e){let t=await d.text(e);return v(t),t}async function b(e){let t=await d.select(e);return v(t),t}async function x(e){let t=await d.multiselect(e);return v(t),t}async function S(e){let t=await d.confirm(e);return v(t),t}function C(){return d.spinner()}const w=d.log;var T=e({generateAgentDocs:()=>M});const E=`.agents`,D=new Set([`rest`,`minimal`,`fullstack`]);function O(e,t){if(t)return t;try{let t=JSON.parse(l(u(e,`package.json`),`utf-8`));if(t.name)return t.name.replace(/^@[^/]+\//,``)}catch{}return e.split(`/`).findLast(Boolean)??`app`}function k(e,t){if(t)return t;try{let t=JSON.parse(l(u(e,`package.json`),`utf-8`));if(t.packageManager)return t.packageManager.split(`@`)[0]}catch{}return`pnpm`}async function A(e){try{return(await t(e))?.modules?.style===`class`?`class`:`define`}catch{return`define`}}async function j(e,n){if(n)return n;try{let n=(await t(e))?.pattern;if(n&&D.has(n))return n}catch{}return`rest`}async function M(e){let t=e.only??`all`,l=O(e.outDir,e.name),d=k(e.outDir,e.pm),f=await j(e.outDir,e.template),p=await A(e.outDir),m=t===`agents`||t===`both`||t===`all`,h=t===`claude`||t===`both`||t===`all`,g=t===`skills`||t===`all`,_=t===`gemini`||t===`all`,v=t===`copilot`||t===`all`,y=[];if(m&&y.push({file:u(e.outDir,E,`AGENTS.md`),render:()=>s(l,f,d)}),h&&y.push({file:u(e.outDir,`CLAUDE.md`),render:()=>a(l,f,d)}),g)for(let t of n(l,f,d,p))y.push({file:u(e.outDir,E,`skills`,t.slug,`SKILL.md`),render:()=>t.content});_&&y.push({file:u(e.outDir,E,`GEMINI.md`),render:()=>r(l,f,d)}),v&&y.push({file:u(e.outDir,E,`COPILOT.md`),render:()=>o(l,f,d)});let b=[];for(let{file:t,render:n}of y){if(c(t)&&!e.force&&!await S({message:`${t.replace(e.outDir+`/`,``)} already exists. Overwrite?`,initialValue:!1})){console.log(` Skipped — existing ${t.replace(e.outDir+`/`,``)} preserved.`);continue}await i(t,n()),b.push(t)}return b}export{w as a,b as c,m as d,f,g as i,C as l,M as n,x as o,h as p,S as r,_ as s,T as t,y as u};
11
+ import{t as e}from"./rolldown-runtime-D-i_dFAb.mjs";import{a as t}from"./config-BYSNxf_t.mjs";import{a as n,i as r,l as i,n as a,r as o,t as s}from"./project-docs-CYCi7cHt.mjs";import{existsSync as c,readFileSync as l}from"node:fs";import{join as u}from"node:path";import*as d from"@clack/prompts";import f from"picocolors";const p={GET:f.green,POST:f.cyan,PUT:f.yellow,PATCH:f.magenta,DELETE:f.red};function m(e){return(p[e]??f.dim)(e.padEnd(7))}function h(e){let t=`[${e}]`.padEnd(10);switch(e){case`CRITICAL`:return f.red(t);case`WARNING`:return f.yellow(t);case`INFO`:return f.blue(f.dim(t));default:return t}}f.green(`✓`),f.red(`✖`),f.yellow(`⚠`),f.blue(`ℹ`);function g(e){d.intro(f.bgCyan(f.black(` ${e} `)))}function _(e){d.outro(e)}function v(e){d.isCancel(e)&&(d.cancel(`Operation cancelled.`),process.exit(0))}async function y(e){let t=await d.text(e);return v(t),t}async function b(e){let t=await d.select(e);return v(t),t}async function x(e){let t=await d.multiselect(e);return v(t),t}async function S(e){let t=await d.confirm(e);return v(t),t}function C(){return d.spinner()}const w=d.log;var T=e({generateAgentDocs:()=>M});const E=`.agents`,D=new Set([`rest`,`minimal`,`fullstack`]);function O(e,t){if(t)return t;try{let t=JSON.parse(l(u(e,`package.json`),`utf-8`));if(t.name)return t.name.replace(/^@[^/]+\//,``)}catch{}return e.split(`/`).findLast(Boolean)??`app`}function k(e,t){if(t)return t;try{let t=JSON.parse(l(u(e,`package.json`),`utf-8`));if(t.packageManager)return t.packageManager.split(`@`)[0]}catch{}return`pnpm`}async function A(e){try{return(await t(e))?.modules?.style===`class`?`class`:`define`}catch{return`define`}}async function j(e,n){if(n)return n;try{let n=(await t(e))?.pattern;if(n&&D.has(n))return n}catch{}return`rest`}async function M(e){let t=e.only??`all`,l=O(e.outDir,e.name),d=k(e.outDir,e.pm),f=await j(e.outDir,e.template),p=await A(e.outDir),m=t===`agents`||t===`both`||t===`all`,h=t===`claude`||t===`both`||t===`all`,g=t===`skills`||t===`all`,_=t===`gemini`||t===`all`,v=t===`copilot`||t===`all`,y=[];if(m&&y.push({file:u(e.outDir,E,`AGENTS.md`),render:()=>s(l,f,d)}),h&&y.push({file:u(e.outDir,`CLAUDE.md`),render:()=>a(l,f,d)}),g)for(let t of n(l,f,d,p))y.push({file:u(e.outDir,E,`skills`,t.slug,`SKILL.md`),render:()=>t.content});_&&y.push({file:u(e.outDir,E,`GEMINI.md`),render:()=>r(l,f,d)}),v&&y.push({file:u(e.outDir,E,`COPILOT.md`),render:()=>o(l,f,d)});let b=[];for(let{file:t,render:n}of y){if(c(t)&&!e.force&&!await S({message:`${t.replace(e.outDir+`/`,``)} already exists. Overwrite?`,initialValue:!1})){console.log(` Skipped — existing ${t.replace(e.outDir+`/`,``)} preserved.`);continue}await i(t,n()),b.push(t)}return b}export{w as a,b as c,m as d,f,g as i,C as l,M as n,x as o,h as p,S as r,_ as s,T as t,y as u};
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs-cli v8.1.5
2
+ * @forinda/kickjs-cli v8.1.6
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,5 +8,5 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{t as e}from"./rolldown-runtime-DmTqmRjS.mjs";import{a as t,i as n,l as r,n as i,r as a,t as o}from"./project-docs-BCwWphge.mjs";import{t as s}from"./prompts-Ba0PO3Rn.mjs";import{o as c}from"./config-D06pHD-Y.mjs";import{join as l}from"node:path";import{existsSync as u,readFileSync as d}from"node:fs";var f=e({generateAgentDocs:()=>y});const p=`.agents`,m=new Set([`rest`,`minimal`,`fullstack`]);function h(e,t){if(t)return t;try{let t=JSON.parse(d(l(e,`package.json`),`utf-8`));if(t.name)return t.name.replace(/^@[^/]+\//,``)}catch{}return e.split(`/`).findLast(Boolean)??`app`}function g(e,t){if(t)return t;try{let t=JSON.parse(d(l(e,`package.json`),`utf-8`));if(t.packageManager)return t.packageManager.split(`@`)[0]}catch{}return`pnpm`}async function _(e){try{return(await c(e))?.modules?.style===`class`?`class`:`define`}catch{return`define`}}async function v(e,t){if(t)return t;try{let t=(await c(e))?.pattern;if(t&&m.has(t))return t}catch{}return`rest`}async function y(e){let c=e.only??`all`,d=h(e.outDir,e.name),f=g(e.outDir,e.pm),m=await v(e.outDir,e.template),y=await _(e.outDir),b=c===`agents`||c===`both`||c===`all`,x=c===`claude`||c===`both`||c===`all`,S=c===`skills`||c===`all`,C=c===`gemini`||c===`all`,w=c===`copilot`||c===`all`,T=[];if(b&&T.push({file:l(e.outDir,p,`AGENTS.md`),render:()=>o(d,m,f)}),x&&T.push({file:l(e.outDir,`CLAUDE.md`),render:()=>i(d,m,f)}),S)for(let n of t(d,m,f,y))T.push({file:l(e.outDir,p,`skills`,n.slug,`SKILL.md`),render:()=>n.content});C&&T.push({file:l(e.outDir,p,`GEMINI.md`),render:()=>n(d,m,f)}),w&&T.push({file:l(e.outDir,p,`COPILOT.md`),render:()=>a(d,m,f)});let E=[];for(let{file:t,render:n}of T){if(u(t)&&!e.force&&!await s({message:`${t.replace(e.outDir+`/`,``)} already exists. Overwrite?`,initialValue:!1})){console.log(` Skipped — existing ${t.replace(e.outDir+`/`,``)} preserved.`);continue}await r(t,n()),E.push(t)}return E}export{y as n,f as t};
12
- //# sourceMappingURL=agent-docs-DzaWoZc7.mjs.map
11
+ import{t as e}from"./rolldown-runtime-D-i_dFAb.mjs";import{a as t,i as n,l as r,n as i,r as a,t as o}from"./project-docs-at2gZlUE.mjs";import{t as s}from"./prompts-BxPTyuY3.mjs";import{o as c}from"./config-DST3ilXt.mjs";import{join as l}from"node:path";import{existsSync as u,readFileSync as d}from"node:fs";var f=e({generateAgentDocs:()=>y});const p=`.agents`,m=new Set([`rest`,`minimal`,`fullstack`]);function h(e,t){if(t)return t;try{let t=JSON.parse(d(l(e,`package.json`),`utf-8`));if(t.name)return t.name.replace(/^@[^/]+\//,``)}catch{}return e.split(`/`).findLast(Boolean)??`app`}function g(e,t){if(t)return t;try{let t=JSON.parse(d(l(e,`package.json`),`utf-8`));if(t.packageManager)return t.packageManager.split(`@`)[0]}catch{}return`pnpm`}async function _(e){try{return(await c(e))?.modules?.style===`class`?`class`:`define`}catch{return`define`}}async function v(e,t){if(t)return t;try{let t=(await c(e))?.pattern;if(t&&m.has(t))return t}catch{}return`rest`}async function y(e){let c=e.only??`all`,d=h(e.outDir,e.name),f=g(e.outDir,e.pm),m=await v(e.outDir,e.template),y=await _(e.outDir),b=c===`agents`||c===`both`||c===`all`,x=c===`claude`||c===`both`||c===`all`,S=c===`skills`||c===`all`,C=c===`gemini`||c===`all`,w=c===`copilot`||c===`all`,T=[];if(b&&T.push({file:l(e.outDir,p,`AGENTS.md`),render:()=>o(d,m,f)}),x&&T.push({file:l(e.outDir,`CLAUDE.md`),render:()=>i(d,m,f)}),S)for(let n of t(d,m,f,y))T.push({file:l(e.outDir,p,`skills`,n.slug,`SKILL.md`),render:()=>n.content});C&&T.push({file:l(e.outDir,p,`GEMINI.md`),render:()=>n(d,m,f)}),w&&T.push({file:l(e.outDir,p,`COPILOT.md`),render:()=>a(d,m,f)});let E=[];for(let{file:t,render:n}of T){if(u(t)&&!e.force&&!await s({message:`${t.replace(e.outDir+`/`,``)} already exists. Overwrite?`,initialValue:!1})){console.log(` Skipped — existing ${t.replace(e.outDir+`/`,``)} preserved.`);continue}await r(t,n()),E.push(t)}return E}export{y as n,f as t};
12
+ //# sourceMappingURL=agent-docs-CW5TQHti.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-docs-DzaWoZc7.mjs","names":[],"sources":["../src/generators/agent-docs.ts"],"sourcesContent":["import { join } from 'node:path'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { writeFileSafe } from '../utils/fs'\nimport { confirm } from '../utils/prompts'\nimport {\n generateClaude,\n generateAgents,\n generateKickJsSkillFiles,\n generateGemini,\n generateCopilot,\n} from './templates/project-docs'\nimport { loadKickConfig } from '../config'\nimport type { ModuleStyle } from './templates/types'\n\ntype ProjectTemplate = 'rest' | 'minimal' | 'fullstack'\n\n/**\n * Subdirectory (relative to the project root) where every shared\n * agent-context file lands. CLAUDE.md is the only exception — it stays\n * at the project root because Claude Code auto-loads CLAUDE.md from\n * there. CLAUDE.md is generated as a thin pointer that tells Claude\n * to read `.agents/AGENTS.md` first.\n *\n * Existing root-level AGENTS.md / kickjs-skills.md files (from older\n * scaffolds before this restructure) are left untouched — the\n * generator emits the new layout alongside them and leaves migration\n * to the adopter.\n */\nconst AGENTS_DIR = '.agents'\n\nexport interface GenerateAgentDocsOptions {\n outDir: string\n /** Override project name (defaults to package.json `name`). */\n name?: string\n /** Override package manager (defaults to package.json `packageManager` field, then 'pnpm'). */\n pm?: string\n /** Override template (defaults to kick.config.ts `pattern`, then 'rest'). */\n template?: ProjectTemplate\n /**\n * Which file(s) to (re)generate. All `.agents/`-bound files land in\n * the project's `.agents/` subdirectory; `claude` is the only file\n * that stays at the project root.\n *\n * - `agents` → `.agents/AGENTS.md`\n * - `claude` → `CLAUDE.md` (root; thin pointer to .agents/)\n * - `skills` → `.agents/skills/<slug>/SKILL.md` (one per skill)\n * - `gemini` → `.agents/GEMINI.md`\n * - `copilot` → `.agents/COPILOT.md`\n * - `both` → `.agents/AGENTS.md` + `CLAUDE.md` (legacy alias)\n * - `all` → every file above\n */\n only?: 'agents' | 'claude' | 'skills' | 'gemini' | 'copilot' | 'both' | 'all'\n /** Skip the overwrite prompt. */\n force?: boolean\n}\n\nconst VALID_TEMPLATES = new Set<ProjectTemplate>(['rest', 'minimal', 'fullstack'])\n\nfunction detectName(outDir: string, override?: string): string {\n if (override) return override\n try {\n const pkg = JSON.parse(readFileSync(join(outDir, 'package.json'), 'utf-8')) as { name?: string }\n if (pkg.name) return pkg.name.replace(/^@[^/]+\\//, '')\n } catch {\n // No package.json — fall back to folder name\n }\n return outDir.split('/').findLast(Boolean) ?? 'app'\n}\n\nfunction detectPm(outDir: string, override?: string): string {\n if (override) return override\n try {\n const pkg = JSON.parse(readFileSync(join(outDir, 'package.json'), 'utf-8')) as {\n packageManager?: string\n }\n if (pkg.packageManager) return pkg.packageManager.split('@')[0]\n } catch {\n // ignore\n }\n return 'pnpm'\n}\n\n/**\n * Module declaration style, so generated examples show the form this project\n * actually uses. A `class` module passed as `UserModule()` calls a class\n * without `new`; a `define` module passed bare is refused when it takes config.\n */\nasync function detectStyle(outDir: string): Promise<ModuleStyle> {\n try {\n const cfg = await loadKickConfig(outDir)\n return cfg?.modules?.style === 'class' ? 'class' : 'define'\n } catch {\n return 'define'\n }\n}\n\nasync function detectTemplate(\n outDir: string,\n override?: ProjectTemplate,\n): Promise<ProjectTemplate> {\n if (override) return override\n try {\n const cfg = await loadKickConfig(outDir)\n const pattern = cfg?.pattern as ProjectTemplate | undefined\n if (pattern && VALID_TEMPLATES.has(pattern)) return pattern\n } catch {\n // ignore\n }\n return 'rest'\n}\n\nexport async function generateAgentDocs(options: GenerateAgentDocsOptions): Promise<string[]> {\n const only = options.only ?? 'all'\n const name = detectName(options.outDir, options.name)\n const pm = detectPm(options.outDir, options.pm)\n const template = await detectTemplate(options.outDir, options.template)\n const style = await detectStyle(options.outDir)\n\n const wantsAgents = only === 'agents' || only === 'both' || only === 'all'\n const wantsClaude = only === 'claude' || only === 'both' || only === 'all'\n const wantsSkills = only === 'skills' || only === 'all'\n const wantsGemini = only === 'gemini' || only === 'all'\n const wantsCopilot = only === 'copilot' || only === 'all'\n\n // CLAUDE.md stays at the project root because Claude Code auto-loads\n // it from there. Every other shared-context file lands under\n // `.agents/` so the root stays uncluttered. `writeFileSafe` creates\n // parent directories automatically — no need to pre-mkdir.\n const targets: { file: string; render: () => string }[] = []\n if (wantsAgents) {\n targets.push({\n file: join(options.outDir, AGENTS_DIR, 'AGENTS.md'),\n render: () => generateAgents(name, template, pm),\n })\n }\n if (wantsClaude) {\n targets.push({\n file: join(options.outDir, 'CLAUDE.md'),\n render: () => generateClaude(name, template, pm),\n })\n }\n if (wantsSkills) {\n // Per-skill SKILL.md under `.agents/skills/<slug>/` so agents that\n // auto-discover skills (Claude Code, Copilot CLI plugins, Gemini's\n // activate_skill) pick each up by its frontmatter without needing\n // a separate index file.\n for (const skill of generateKickJsSkillFiles(name, template, pm, style)) {\n targets.push({\n file: join(options.outDir, AGENTS_DIR, 'skills', skill.slug, 'SKILL.md'),\n render: () => skill.content,\n })\n }\n }\n if (wantsGemini) {\n targets.push({\n file: join(options.outDir, AGENTS_DIR, 'GEMINI.md'),\n render: () => generateGemini(name, template, pm),\n })\n }\n if (wantsCopilot) {\n targets.push({\n file: join(options.outDir, AGENTS_DIR, 'COPILOT.md'),\n render: () => generateCopilot(name, template, pm),\n })\n }\n\n const written: string[] = []\n for (const { file, render } of targets) {\n if (existsSync(file) && !options.force) {\n const overwrite = await confirm({\n message: `${file.replace(options.outDir + '/', '')} already exists. Overwrite?`,\n initialValue: false,\n })\n if (!overwrite) {\n console.log(` Skipped — existing ${file.replace(options.outDir + '/', '')} preserved.`)\n continue\n }\n }\n await writeFileSafe(file, render())\n written.push(file)\n }\n return written\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"agent-docs-CW5TQHti.mjs","names":[],"sources":["../src/generators/agent-docs.ts"],"sourcesContent":["import { join } from 'node:path'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { writeFileSafe } from '../utils/fs'\nimport { confirm } from '../utils/prompts'\nimport {\n generateClaude,\n generateAgents,\n generateKickJsSkillFiles,\n generateGemini,\n generateCopilot,\n} from './templates/project-docs'\nimport { loadKickConfig } from '../config'\nimport type { ModuleStyle } from './templates/types'\n\ntype ProjectTemplate = 'rest' | 'minimal' | 'fullstack'\n\n/**\n * Subdirectory (relative to the project root) where every shared\n * agent-context file lands. CLAUDE.md is the only exception — it stays\n * at the project root because Claude Code auto-loads CLAUDE.md from\n * there. CLAUDE.md is generated as a thin pointer that tells Claude\n * to read `.agents/AGENTS.md` first.\n *\n * Existing root-level AGENTS.md / kickjs-skills.md files (from older\n * scaffolds before this restructure) are left untouched — the\n * generator emits the new layout alongside them and leaves migration\n * to the adopter.\n */\nconst AGENTS_DIR = '.agents'\n\nexport interface GenerateAgentDocsOptions {\n outDir: string\n /** Override project name (defaults to package.json `name`). */\n name?: string\n /** Override package manager (defaults to package.json `packageManager` field, then 'pnpm'). */\n pm?: string\n /** Override template (defaults to kick.config.ts `pattern`, then 'rest'). */\n template?: ProjectTemplate\n /**\n * Which file(s) to (re)generate. All `.agents/`-bound files land in\n * the project's `.agents/` subdirectory; `claude` is the only file\n * that stays at the project root.\n *\n * - `agents` → `.agents/AGENTS.md`\n * - `claude` → `CLAUDE.md` (root; thin pointer to .agents/)\n * - `skills` → `.agents/skills/<slug>/SKILL.md` (one per skill)\n * - `gemini` → `.agents/GEMINI.md`\n * - `copilot` → `.agents/COPILOT.md`\n * - `both` → `.agents/AGENTS.md` + `CLAUDE.md` (legacy alias)\n * - `all` → every file above\n */\n only?: 'agents' | 'claude' | 'skills' | 'gemini' | 'copilot' | 'both' | 'all'\n /** Skip the overwrite prompt. */\n force?: boolean\n}\n\nconst VALID_TEMPLATES = new Set<ProjectTemplate>(['rest', 'minimal', 'fullstack'])\n\nfunction detectName(outDir: string, override?: string): string {\n if (override) return override\n try {\n const pkg = JSON.parse(readFileSync(join(outDir, 'package.json'), 'utf-8')) as { name?: string }\n if (pkg.name) return pkg.name.replace(/^@[^/]+\\//, '')\n } catch {\n // No package.json — fall back to folder name\n }\n return outDir.split('/').findLast(Boolean) ?? 'app'\n}\n\nfunction detectPm(outDir: string, override?: string): string {\n if (override) return override\n try {\n const pkg = JSON.parse(readFileSync(join(outDir, 'package.json'), 'utf-8')) as {\n packageManager?: string\n }\n if (pkg.packageManager) return pkg.packageManager.split('@')[0]\n } catch {\n // ignore\n }\n return 'pnpm'\n}\n\n/**\n * Module declaration style, so generated examples show the form this project\n * actually uses. A `class` module passed as `UserModule()` calls a class\n * without `new`; a `define` module passed bare is refused when it takes config.\n */\nasync function detectStyle(outDir: string): Promise<ModuleStyle> {\n try {\n const cfg = await loadKickConfig(outDir)\n return cfg?.modules?.style === 'class' ? 'class' : 'define'\n } catch {\n return 'define'\n }\n}\n\nasync function detectTemplate(\n outDir: string,\n override?: ProjectTemplate,\n): Promise<ProjectTemplate> {\n if (override) return override\n try {\n const cfg = await loadKickConfig(outDir)\n const pattern = cfg?.pattern as ProjectTemplate | undefined\n if (pattern && VALID_TEMPLATES.has(pattern)) return pattern\n } catch {\n // ignore\n }\n return 'rest'\n}\n\nexport async function generateAgentDocs(options: GenerateAgentDocsOptions): Promise<string[]> {\n const only = options.only ?? 'all'\n const name = detectName(options.outDir, options.name)\n const pm = detectPm(options.outDir, options.pm)\n const template = await detectTemplate(options.outDir, options.template)\n const style = await detectStyle(options.outDir)\n\n const wantsAgents = only === 'agents' || only === 'both' || only === 'all'\n const wantsClaude = only === 'claude' || only === 'both' || only === 'all'\n const wantsSkills = only === 'skills' || only === 'all'\n const wantsGemini = only === 'gemini' || only === 'all'\n const wantsCopilot = only === 'copilot' || only === 'all'\n\n // CLAUDE.md stays at the project root because Claude Code auto-loads\n // it from there. Every other shared-context file lands under\n // `.agents/` so the root stays uncluttered. `writeFileSafe` creates\n // parent directories automatically — no need to pre-mkdir.\n const targets: { file: string; render: () => string }[] = []\n if (wantsAgents) {\n targets.push({\n file: join(options.outDir, AGENTS_DIR, 'AGENTS.md'),\n render: () => generateAgents(name, template, pm),\n })\n }\n if (wantsClaude) {\n targets.push({\n file: join(options.outDir, 'CLAUDE.md'),\n render: () => generateClaude(name, template, pm),\n })\n }\n if (wantsSkills) {\n // Per-skill SKILL.md under `.agents/skills/<slug>/` so agents that\n // auto-discover skills (Claude Code, Copilot CLI plugins, Gemini's\n // activate_skill) pick each up by its frontmatter without needing\n // a separate index file.\n for (const skill of generateKickJsSkillFiles(name, template, pm, style)) {\n targets.push({\n file: join(options.outDir, AGENTS_DIR, 'skills', skill.slug, 'SKILL.md'),\n render: () => skill.content,\n })\n }\n }\n if (wantsGemini) {\n targets.push({\n file: join(options.outDir, AGENTS_DIR, 'GEMINI.md'),\n render: () => generateGemini(name, template, pm),\n })\n }\n if (wantsCopilot) {\n targets.push({\n file: join(options.outDir, AGENTS_DIR, 'COPILOT.md'),\n render: () => generateCopilot(name, template, pm),\n })\n }\n\n const written: string[] = []\n for (const { file, render } of targets) {\n if (existsSync(file) && !options.force) {\n const overwrite = await confirm({\n message: `${file.replace(options.outDir + '/', '')} already exists. Overwrite?`,\n initialValue: false,\n })\n if (!overwrite) {\n console.log(` Skipped — existing ${file.replace(options.outDir + '/', '')} preserved.`)\n continue\n }\n }\n await writeFileSafe(file, render())\n written.push(file)\n }\n return written\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs-cli v8.1.5
2
+ * @forinda/kickjs-cli v8.1.6
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,6 +8,6 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{t as e}from"./rolldown-runtime-DmTqmRjS.mjs";import{dirname as t,isAbsolute as n,join as r,relative as i,resolve as a}from"node:path";import{cpSync as o,existsSync as s,mkdirSync as c,statSync as l,writeFileSync as u}from"node:fs";import{glob as d}from"glob";import{groupAssetKeys as f}from"@forinda/kickjs";var p=e({ASSET_MANIFEST_VERSION:()=>1,buildAssets:()=>m});async function m(e,t){let{cwd:n,silent:o=!1}=t,s=t.distDir??e?.build?.outDir??`dist`,l=e?.assetMap;if(!l||Object.keys(l).length===0)return null;let d=o?()=>{}:console.log,f=a(n,s);c(f,{recursive:!0});let p=[],m={};for(let[e,t]of Object.entries(l)){let r=await h(e,t,n,f);p.push(r.entrySummary),Object.assign(m,r.manifestSlice),d(` ✓ ${e}: ${r.entrySummary.filesCopied} file(s) → ${r.entrySummary.dest}`)}let g={version:1,entries:m},_=r(f,`.kickjs-assets.json`);return u(_,JSON.stringify(g,null,2)+`
11
+ import{t as e}from"./rolldown-runtime-D-i_dFAb.mjs";import{dirname as t,isAbsolute as n,join as r,relative as i,resolve as a}from"node:path";import{cpSync as o,existsSync as s,mkdirSync as c,statSync as l,writeFileSync as u}from"node:fs";import{glob as d}from"glob";import{groupAssetKeys as f}from"@forinda/kickjs";var p=e({ASSET_MANIFEST_VERSION:()=>1,buildAssets:()=>m});async function m(e,t){let{cwd:n,silent:o=!1}=t,s=t.distDir??e?.build?.outDir??`dist`,l=e?.assetMap;if(!l||Object.keys(l).length===0)return null;let d=o?()=>{}:console.log,f=a(n,s);c(f,{recursive:!0});let p=[],m={};for(let[e,t]of Object.entries(l)){let r=await h(e,t,n,f);p.push(r.entrySummary),Object.assign(m,r.manifestSlice),d(` ✓ ${e}: ${r.entrySummary.filesCopied} file(s) → ${r.entrySummary.dest}`)}let g={version:1,entries:m},_=r(f,`.kickjs-assets.json`);return u(_,JSON.stringify(g,null,2)+`
12
12
  `,`utf-8`),d(` ✓ wrote manifest → ${i(n,_)} (${Object.keys(m).length} entries)`),{manifestPath:_,entries:p,manifest:g}}async function h(e,n,l,u){let p=a(l,n.src),m=n.dest?a(l,n.dest):r(u,e);if(v(m,l))return console.warn(` ⚠ assetMap.${e}.dest ('${n.dest}') resolves outside the project root — skipping copy`),{entrySummary:{namespace:e,src:n.src,dest:i(l,m),filesCopied:0},manifestSlice:{}};if(!s(p)||!y(p))return{entrySummary:{namespace:e,src:n.src,dest:i(l,m),filesCopied:0},manifestSlice:{}};let h=await d(n.glob??`**/*`,{cwd:p,nodir:!0,dot:!1,posix:!0});c(m,{recursive:!0});let b={},{pairs:x,collisionGroupsResolved:S}=f(e,[...h].toSorted(),{strategy:n.keys??`auto`}),C=0;for(let{rel:e,key:n}of x){let i=r(p,e),a=r(m,e);b[n]=_(u,a),!g(i,a)&&(c(t(a),{recursive:!0}),o(i,a),C++)}return S>0&&console.log(` ℹ assetMap.${e}: auto-resolved ${S} 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:n.src,dest:i(l,m),filesCopied:C},manifestSlice:b}}function g(e,t){if(!s(t))return!1;try{let n=l(e),r=l(t);return r.size===n.size&&r.mtimeMs>=n.mtimeMs}catch{return!1}}function _(e,t){return i(e,t).split(/[\\/]/).filter(Boolean).join(`/`)}function v(e,t){let r=i(t,e);return r===``?!1:r.startsWith(`..`)||n(r)}function y(e){try{return l(e).isDirectory()}catch{return!1}}export{p as n,m as t};
13
- //# sourceMappingURL=build-DBT23vXN.mjs.map
13
+ //# sourceMappingURL=build-DOI_zYDS.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-DBT23vXN.mjs","names":[],"sources":["../src/asset-manager/build.ts"],"sourcesContent":["/**\n * Build pipeline for `assetMap` entries (asset-manager PR 2).\n *\n * For each entry, walks `src/<...>` matching the configured `glob`,\n * copies matches into `dest` (default `dist/<name>/`), then emits a\n * `dist/.kickjs-assets.json` manifest mapping logical\n * `<namespace>/<key>` keys to repo-relative paths inside `dist/`.\n *\n * Pure function on top of `node:fs` + `glob` — no shell, no side\n * effects beyond the configured directory writes. The build entry-\n * point in `commands/run.ts` calls `buildAssets` after the existing\n * `copyDirs` step.\n *\n * @module @forinda/kickjs-cli/asset-manager/build\n */\n\nimport { cpSync, existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs'\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path'\nimport { glob } from 'glob'\nimport { groupAssetKeys } from '@forinda/kickjs'\nimport type { AssetMapEntry, KickConfig } from '../config'\n\n/** Wire-format version for `dist/.kickjs-assets.json`. Bump on shape change. */\nexport const ASSET_MANIFEST_VERSION = 1 as const\n\n/** On-disk manifest format (`dist/.kickjs-assets.json`). */\nexport interface AssetManifest {\n version: typeof ASSET_MANIFEST_VERSION\n /**\n * Logical key → manifest-relative path. Logical key is\n * `<namespace>/<key>` where `<key>` is the file path under `src`\n * with the extension stripped + path separators normalised.\n *\n * Path values are relative to the manifest file's directory so the\n * runtime can resolve them with a single `path.resolve(manifestDir,\n * entry)` regardless of where dist/ lives.\n */\n entries: Record<string, string>\n}\n\nexport interface BuildAssetsOptions {\n /** Project root — resolved for every relative path in the entry. */\n cwd: string\n /**\n * Output dir for the manifest + per-namespace asset copies. When\n * omitted, falls back to `config.build?.outDir` (resolved against\n * `cwd`), then to `dist/` under cwd. Adopters with a custom Vite\n * `build.outDir` should set `kick.config.ts.build.outDir` to match.\n */\n distDir?: string\n /** Suppress per-entry log lines. Default: false. */\n silent?: boolean\n}\n\n/** One entry in the per-build summary returned by `buildAssets`. */\nexport interface BuildAssetsEntryResult {\n namespace: string\n src: string\n dest: string\n /**\n * Number of files actually written this run. On an incremental\n * rebuild where nothing changed this is 0 even though the manifest\n * still lists every matched file.\n */\n filesCopied: number\n}\n\n/** Aggregated outcome of `buildAssets`. */\nexport interface BuildAssetsResult {\n manifestPath: string\n entries: BuildAssetsEntryResult[]\n /** `entries` merged into a single record — useful for tests + tooling. */\n manifest: AssetManifest\n}\n\n/**\n * Run the full asset build for a loaded config:\n *\n * 1. For each `assetMap` entry, glob → copy → manifest stub.\n * 2. Write `dist/.kickjs-assets.json`.\n *\n * Returns a summary including the manifest contents. No-op (and no\n * manifest written) when `assetMap` is empty / missing — the build\n * pipeline shouldn't litter `dist/` with empty manifests for\n * adopters who don't use the feature.\n */\nexport async function buildAssets(\n config: KickConfig | null,\n opts: BuildAssetsOptions,\n): Promise<BuildAssetsResult | null> {\n const { cwd, silent = false } = opts\n // Resolution order: explicit opts.distDir → config.build.outDir → 'dist'.\n // The CLI build command passes nothing explicit, so adopters control\n // the output via kick.config.ts.build.outDir alone.\n const distDir = opts.distDir ?? config?.build?.outDir ?? 'dist'\n const map = config?.assetMap\n if (!map || Object.keys(map).length === 0) return null\n\n const log = silent ? () => {} : console.log\n\n const distAbs = resolve(cwd, distDir)\n mkdirSync(distAbs, { recursive: true })\n\n const summary: BuildAssetsEntryResult[] = []\n const manifestEntries: Record<string, string> = {}\n\n for (const [namespace, entry] of Object.entries(map)) {\n const result = await processEntry(namespace, entry, cwd, distAbs)\n summary.push(result.entrySummary)\n Object.assign(manifestEntries, result.manifestSlice)\n log(\n ` ✓ ${namespace}: ${result.entrySummary.filesCopied} file(s) → ${result.entrySummary.dest}`,\n )\n }\n\n const manifest: AssetManifest = {\n version: ASSET_MANIFEST_VERSION,\n entries: manifestEntries,\n }\n const manifestPath = join(distAbs, '.kickjs-assets.json')\n writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\\n', 'utf-8')\n log(\n ` ✓ wrote manifest → ${relative(cwd, manifestPath)} (${Object.keys(manifestEntries).length} entries)`,\n )\n\n return { manifestPath, entries: summary, manifest }\n}\n\n/** Per-entry inner pipeline — extracted for unit-test reuse. */\nasync function processEntry(\n namespace: string,\n entry: AssetMapEntry,\n cwd: string,\n distAbs: string,\n): Promise<{\n entrySummary: BuildAssetsEntryResult\n manifestSlice: Record<string, string>\n}> {\n const srcAbs = resolve(cwd, entry.src)\n const destAbs = entry.dest ? resolve(cwd, entry.dest) : join(distAbs, namespace)\n\n // Defensive: refuse to write outside the project root (cwd) even\n // though validateAssetMap warned about it at config-load time. The\n // build step shouldn't trust upstream warnings — a typo like\n // `dest: '../../'` would otherwise sprinkle files outside the\n // workspace despite the warning being printed.\n if (escapesRoot(destAbs, cwd)) {\n console.warn(\n ` ⚠ assetMap.${namespace}.dest ('${entry.dest}') resolves outside the project root — skipping copy`,\n )\n return {\n entrySummary: { namespace, src: entry.src, dest: relative(cwd, destAbs), filesCopied: 0 },\n manifestSlice: {},\n }\n }\n\n // Treat src-not-a-directory the same as src-missing — `glob` would\n // throw if pointed at a file, surfacing as a generic build failure\n // instead of a clean 0-files entry. Matches the validator's warning\n // shape (already emitted at config-load time for the missing case).\n if (!existsSync(srcAbs) || !isDirectorySync(srcAbs)) {\n return {\n entrySummary: { namespace, src: entry.src, dest: relative(cwd, destAbs), filesCopied: 0 },\n manifestSlice: {},\n }\n }\n\n const pattern = entry.glob ?? '**/*'\n // `glob` returns paths relative to `cwd` when `cwd` is set —\n // exactly the slugs we want for the manifest keys.\n const matches = await glob(pattern, {\n cwd: srcAbs,\n nodir: true,\n dot: false,\n posix: true,\n })\n\n mkdirSync(destAbs, { recursive: true })\n\n const manifestSlice: Record<string, string> = {}\n // Sort the walk so the manifest is byte-stable across platforms.\n // The `groupAssetKeys` helper preserves input order, so a stable\n // sort here makes the resulting manifest stable too.\n const sorted = [...matches].toSorted()\n const { pairs, collisionGroupsResolved } = groupAssetKeys(namespace, sorted, {\n strategy: entry.keys ?? 'auto',\n })\n\n // Copy the files and write the keyed manifest slice. Both come from\n // the same `pairs` order so the on-disk layout matches the\n // manifest's iteration order — easier to grep in cold-start\n // debugging.\n //\n // Incremental: skip the copy when the destination is already\n // up-to-date (exists, same size, mtime ≥ source). `cpSync` stamps the\n // copy with the current time, so an unchanged source always satisfies\n // `dest.mtime ≥ src.mtime` on the next run — turning a re-build into a\n // pure stat sweep instead of re-copying every asset. The manifest\n // slice is written unconditionally so the manifest stays complete.\n let filesCopied = 0\n for (const { rel: relPath, key } of pairs) {\n const srcFile = join(srcAbs, relPath)\n const destFile = join(destAbs, relPath)\n manifestSlice[key] = toManifestRelative(distAbs, destFile)\n if (isUpToDate(srcFile, destFile)) continue\n mkdirSync(dirname(destFile), { recursive: true })\n cpSync(srcFile, destFile)\n filesCopied++\n }\n\n if (collisionGroupsResolved > 0) {\n console.log(\n ` ℹ assetMap.${namespace}: auto-resolved ${collisionGroupsResolved} basename collision(s) by keeping extensions ` +\n `(set 'keys: \"strip\"' to opt back into legacy last-write-wins behaviour, or 'keys: \"with-extension\"' to keep all keys verbose).`,\n )\n }\n\n return {\n entrySummary: {\n namespace,\n src: entry.src,\n dest: relative(cwd, destAbs),\n filesCopied,\n },\n manifestSlice,\n }\n}\n\n/**\n * Is `destFile` already a current copy of `srcFile`? True when the\n * destination exists with the same byte size and an mtime no older than\n * the source. Used to skip redundant copies on an incremental rebuild.\n */\nfunction isUpToDate(srcFile: string, destFile: string): boolean {\n if (!existsSync(destFile)) return false\n try {\n const s = statSync(srcFile)\n const d = statSync(destFile)\n return d.size === s.size && d.mtimeMs >= s.mtimeMs\n } catch {\n return false\n }\n}\n\n/**\n * Make `destFile` relative to the manifest's directory + force POSIX\n * separators so the manifest is byte-stable across platforms.\n */\nfunction toManifestRelative(manifestDir: string, destFile: string): string {\n const rel = relative(manifestDir, destFile)\n // path.relative returns OS-native separators; the manifest is JSON\n // and the runtime uses path.resolve which handles either, but a\n // forward-slash manifest is grep-friendly + diff-stable.\n return rel.split(/[\\\\/]/).filter(Boolean).join('/')\n}\n\n/**\n * Pure manifest writer — handy for tests that want to assert against\n * a hand-crafted manifest without exercising the full pipeline.\n */\nexport function writeAssetManifest(distDir: string, manifest: AssetManifest): string {\n const path = join(distDir, '.kickjs-assets.json')\n mkdirSync(distDir, { recursive: true })\n writeFileSync(path, JSON.stringify(manifest, null, 2) + '\\n', 'utf-8')\n return path\n}\n\n/**\n * Read + parse a manifest from disk. Returns `null` on missing or\n * malformed file rather than throwing — the runtime resolver wants\n * to fall through to dev-mode lookup in that case.\n */\nexport function readAssetManifest(distDir: string): AssetManifest | null {\n const path = join(distDir, '.kickjs-assets.json')\n if (!existsSync(path)) return null\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const fs = require('node:fs') as typeof import('node:fs')\n const raw = fs.readFileSync(path, 'utf-8')\n const parsed = JSON.parse(raw) as Partial<AssetManifest>\n if (parsed.version !== ASSET_MANIFEST_VERSION) return null\n if (!parsed.entries || typeof parsed.entries !== 'object') return null\n return parsed as AssetManifest\n } catch {\n return null\n }\n}\n\n/**\n * Project-root escape check that's safe across symlinks + drive letters.\n * `path.relative` returns `..` segments when the target sits above root,\n * and an absolute path when the two live on different roots (Windows).\n * `startsWith(root)` would miss both cases.\n */\nfunction escapesRoot(path: string, root: string): boolean {\n const rel = relative(root, path)\n if (rel === '') return false\n return rel.startsWith('..') || isAbsolute(rel)\n}\n\n/** Pure helper — `false` for missing, non-dir, or unreadable paths. */\nfunction isDirectorySync(path: string): boolean {\n try {\n return statSync(path).isDirectory()\n } catch {\n return false\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"build-DOI_zYDS.mjs","names":[],"sources":["../src/asset-manager/build.ts"],"sourcesContent":["/**\n * Build pipeline for `assetMap` entries (asset-manager PR 2).\n *\n * For each entry, walks `src/<...>` matching the configured `glob`,\n * copies matches into `dest` (default `dist/<name>/`), then emits a\n * `dist/.kickjs-assets.json` manifest mapping logical\n * `<namespace>/<key>` keys to repo-relative paths inside `dist/`.\n *\n * Pure function on top of `node:fs` + `glob` — no shell, no side\n * effects beyond the configured directory writes. The build entry-\n * point in `commands/run.ts` calls `buildAssets` after the existing\n * `copyDirs` step.\n *\n * @module @forinda/kickjs-cli/asset-manager/build\n */\n\nimport { cpSync, existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs'\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path'\nimport { glob } from 'glob'\nimport { groupAssetKeys } from '@forinda/kickjs'\nimport type { AssetMapEntry, KickConfig } from '../config'\n\n/** Wire-format version for `dist/.kickjs-assets.json`. Bump on shape change. */\nexport const ASSET_MANIFEST_VERSION = 1 as const\n\n/** On-disk manifest format (`dist/.kickjs-assets.json`). */\nexport interface AssetManifest {\n version: typeof ASSET_MANIFEST_VERSION\n /**\n * Logical key → manifest-relative path. Logical key is\n * `<namespace>/<key>` where `<key>` is the file path under `src`\n * with the extension stripped + path separators normalised.\n *\n * Path values are relative to the manifest file's directory so the\n * runtime can resolve them with a single `path.resolve(manifestDir,\n * entry)` regardless of where dist/ lives.\n */\n entries: Record<string, string>\n}\n\nexport interface BuildAssetsOptions {\n /** Project root — resolved for every relative path in the entry. */\n cwd: string\n /**\n * Output dir for the manifest + per-namespace asset copies. When\n * omitted, falls back to `config.build?.outDir` (resolved against\n * `cwd`), then to `dist/` under cwd. Adopters with a custom Vite\n * `build.outDir` should set `kick.config.ts.build.outDir` to match.\n */\n distDir?: string\n /** Suppress per-entry log lines. Default: false. */\n silent?: boolean\n}\n\n/** One entry in the per-build summary returned by `buildAssets`. */\nexport interface BuildAssetsEntryResult {\n namespace: string\n src: string\n dest: string\n /**\n * Number of files actually written this run. On an incremental\n * rebuild where nothing changed this is 0 even though the manifest\n * still lists every matched file.\n */\n filesCopied: number\n}\n\n/** Aggregated outcome of `buildAssets`. */\nexport interface BuildAssetsResult {\n manifestPath: string\n entries: BuildAssetsEntryResult[]\n /** `entries` merged into a single record — useful for tests + tooling. */\n manifest: AssetManifest\n}\n\n/**\n * Run the full asset build for a loaded config:\n *\n * 1. For each `assetMap` entry, glob → copy → manifest stub.\n * 2. Write `dist/.kickjs-assets.json`.\n *\n * Returns a summary including the manifest contents. No-op (and no\n * manifest written) when `assetMap` is empty / missing — the build\n * pipeline shouldn't litter `dist/` with empty manifests for\n * adopters who don't use the feature.\n */\nexport async function buildAssets(\n config: KickConfig | null,\n opts: BuildAssetsOptions,\n): Promise<BuildAssetsResult | null> {\n const { cwd, silent = false } = opts\n // Resolution order: explicit opts.distDir → config.build.outDir → 'dist'.\n // The CLI build command passes nothing explicit, so adopters control\n // the output via kick.config.ts.build.outDir alone.\n const distDir = opts.distDir ?? config?.build?.outDir ?? 'dist'\n const map = config?.assetMap\n if (!map || Object.keys(map).length === 0) return null\n\n const log = silent ? () => {} : console.log\n\n const distAbs = resolve(cwd, distDir)\n mkdirSync(distAbs, { recursive: true })\n\n const summary: BuildAssetsEntryResult[] = []\n const manifestEntries: Record<string, string> = {}\n\n for (const [namespace, entry] of Object.entries(map)) {\n const result = await processEntry(namespace, entry, cwd, distAbs)\n summary.push(result.entrySummary)\n Object.assign(manifestEntries, result.manifestSlice)\n log(\n ` ✓ ${namespace}: ${result.entrySummary.filesCopied} file(s) → ${result.entrySummary.dest}`,\n )\n }\n\n const manifest: AssetManifest = {\n version: ASSET_MANIFEST_VERSION,\n entries: manifestEntries,\n }\n const manifestPath = join(distAbs, '.kickjs-assets.json')\n writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\\n', 'utf-8')\n log(\n ` ✓ wrote manifest → ${relative(cwd, manifestPath)} (${Object.keys(manifestEntries).length} entries)`,\n )\n\n return { manifestPath, entries: summary, manifest }\n}\n\n/** Per-entry inner pipeline — extracted for unit-test reuse. */\nasync function processEntry(\n namespace: string,\n entry: AssetMapEntry,\n cwd: string,\n distAbs: string,\n): Promise<{\n entrySummary: BuildAssetsEntryResult\n manifestSlice: Record<string, string>\n}> {\n const srcAbs = resolve(cwd, entry.src)\n const destAbs = entry.dest ? resolve(cwd, entry.dest) : join(distAbs, namespace)\n\n // Defensive: refuse to write outside the project root (cwd) even\n // though validateAssetMap warned about it at config-load time. The\n // build step shouldn't trust upstream warnings — a typo like\n // `dest: '../../'` would otherwise sprinkle files outside the\n // workspace despite the warning being printed.\n if (escapesRoot(destAbs, cwd)) {\n console.warn(\n ` ⚠ assetMap.${namespace}.dest ('${entry.dest}') resolves outside the project root — skipping copy`,\n )\n return {\n entrySummary: { namespace, src: entry.src, dest: relative(cwd, destAbs), filesCopied: 0 },\n manifestSlice: {},\n }\n }\n\n // Treat src-not-a-directory the same as src-missing — `glob` would\n // throw if pointed at a file, surfacing as a generic build failure\n // instead of a clean 0-files entry. Matches the validator's warning\n // shape (already emitted at config-load time for the missing case).\n if (!existsSync(srcAbs) || !isDirectorySync(srcAbs)) {\n return {\n entrySummary: { namespace, src: entry.src, dest: relative(cwd, destAbs), filesCopied: 0 },\n manifestSlice: {},\n }\n }\n\n const pattern = entry.glob ?? '**/*'\n // `glob` returns paths relative to `cwd` when `cwd` is set —\n // exactly the slugs we want for the manifest keys.\n const matches = await glob(pattern, {\n cwd: srcAbs,\n nodir: true,\n dot: false,\n posix: true,\n })\n\n mkdirSync(destAbs, { recursive: true })\n\n const manifestSlice: Record<string, string> = {}\n // Sort the walk so the manifest is byte-stable across platforms.\n // The `groupAssetKeys` helper preserves input order, so a stable\n // sort here makes the resulting manifest stable too.\n const sorted = [...matches].toSorted()\n const { pairs, collisionGroupsResolved } = groupAssetKeys(namespace, sorted, {\n strategy: entry.keys ?? 'auto',\n })\n\n // Copy the files and write the keyed manifest slice. Both come from\n // the same `pairs` order so the on-disk layout matches the\n // manifest's iteration order — easier to grep in cold-start\n // debugging.\n //\n // Incremental: skip the copy when the destination is already\n // up-to-date (exists, same size, mtime ≥ source). `cpSync` stamps the\n // copy with the current time, so an unchanged source always satisfies\n // `dest.mtime ≥ src.mtime` on the next run — turning a re-build into a\n // pure stat sweep instead of re-copying every asset. The manifest\n // slice is written unconditionally so the manifest stays complete.\n let filesCopied = 0\n for (const { rel: relPath, key } of pairs) {\n const srcFile = join(srcAbs, relPath)\n const destFile = join(destAbs, relPath)\n manifestSlice[key] = toManifestRelative(distAbs, destFile)\n if (isUpToDate(srcFile, destFile)) continue\n mkdirSync(dirname(destFile), { recursive: true })\n cpSync(srcFile, destFile)\n filesCopied++\n }\n\n if (collisionGroupsResolved > 0) {\n console.log(\n ` ℹ assetMap.${namespace}: auto-resolved ${collisionGroupsResolved} basename collision(s) by keeping extensions ` +\n `(set 'keys: \"strip\"' to opt back into legacy last-write-wins behaviour, or 'keys: \"with-extension\"' to keep all keys verbose).`,\n )\n }\n\n return {\n entrySummary: {\n namespace,\n src: entry.src,\n dest: relative(cwd, destAbs),\n filesCopied,\n },\n manifestSlice,\n }\n}\n\n/**\n * Is `destFile` already a current copy of `srcFile`? True when the\n * destination exists with the same byte size and an mtime no older than\n * the source. Used to skip redundant copies on an incremental rebuild.\n */\nfunction isUpToDate(srcFile: string, destFile: string): boolean {\n if (!existsSync(destFile)) return false\n try {\n const s = statSync(srcFile)\n const d = statSync(destFile)\n return d.size === s.size && d.mtimeMs >= s.mtimeMs\n } catch {\n return false\n }\n}\n\n/**\n * Make `destFile` relative to the manifest's directory + force POSIX\n * separators so the manifest is byte-stable across platforms.\n */\nfunction toManifestRelative(manifestDir: string, destFile: string): string {\n const rel = relative(manifestDir, destFile)\n // path.relative returns OS-native separators; the manifest is JSON\n // and the runtime uses path.resolve which handles either, but a\n // forward-slash manifest is grep-friendly + diff-stable.\n return rel.split(/[\\\\/]/).filter(Boolean).join('/')\n}\n\n/**\n * Pure manifest writer — handy for tests that want to assert against\n * a hand-crafted manifest without exercising the full pipeline.\n */\nexport function writeAssetManifest(distDir: string, manifest: AssetManifest): string {\n const path = join(distDir, '.kickjs-assets.json')\n mkdirSync(distDir, { recursive: true })\n writeFileSync(path, JSON.stringify(manifest, null, 2) + '\\n', 'utf-8')\n return path\n}\n\n/**\n * Read + parse a manifest from disk. Returns `null` on missing or\n * malformed file rather than throwing — the runtime resolver wants\n * to fall through to dev-mode lookup in that case.\n */\nexport function readAssetManifest(distDir: string): AssetManifest | null {\n const path = join(distDir, '.kickjs-assets.json')\n if (!existsSync(path)) return null\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const fs = require('node:fs') as typeof import('node:fs')\n const raw = fs.readFileSync(path, 'utf-8')\n const parsed = JSON.parse(raw) as Partial<AssetManifest>\n if (parsed.version !== ASSET_MANIFEST_VERSION) return null\n if (!parsed.entries || typeof parsed.entries !== 'object') return null\n return parsed as AssetManifest\n } catch {\n return null\n }\n}\n\n/**\n * Project-root escape check that's safe across symlinks + drive letters.\n * `path.relative` returns `..` segments when the target sits above root,\n * and an absolute path when the two live on different roots (Windows).\n * `startsWith(root)` would miss both cases.\n */\nfunction escapesRoot(path: string, root: string): boolean {\n const rel = relative(root, path)\n if (rel === '') return false\n return rel.startsWith('..') || isAbsolute(rel)\n}\n\n/** Pure helper — `false` for missing, non-dir, or unreadable paths. */\nfunction isDirectorySync(path: string): boolean {\n try {\n return statSync(path).isDirectory()\n } catch {\n return false\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs-cli v8.1.5
2
+ * @forinda/kickjs-cli v8.1.6
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,5 +8,5 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{t as e}from"./rolldown-runtime-DmTqmRjS.mjs";import{cpSync as t,existsSync as n,mkdirSync as r,statSync as i,writeFileSync as a}from"node:fs";import{dirname as o,isAbsolute as s,join as c,relative as l,resolve as u}from"node:path";import{glob as d}from"glob";import{groupAssetKeys as f}from"@forinda/kickjs";var p=e({ASSET_MANIFEST_VERSION:()=>1,buildAssets:()=>m});async function m(e,t){let{cwd:n,silent:i=!1}=t,o=t.distDir??e?.build?.outDir??`dist`,s=e?.assetMap;if(!s||Object.keys(s).length===0)return null;let d=i?()=>{}:console.log,f=u(n,o);r(f,{recursive:!0});let p=[],m={};for(let[e,t]of Object.entries(s)){let r=await h(e,t,n,f);p.push(r.entrySummary),Object.assign(m,r.manifestSlice),d(` ✓ ${e}: ${r.entrySummary.filesCopied} file(s) → ${r.entrySummary.dest}`)}let g={version:1,entries:m},_=c(f,`.kickjs-assets.json`);return a(_,JSON.stringify(g,null,2)+`
11
+ import{t as e}from"./rolldown-runtime-D-i_dFAb.mjs";import{cpSync as t,existsSync as n,mkdirSync as r,statSync as i,writeFileSync as a}from"node:fs";import{dirname as o,isAbsolute as s,join as c,relative as l,resolve as u}from"node:path";import{glob as d}from"glob";import{groupAssetKeys as f}from"@forinda/kickjs";var p=e({ASSET_MANIFEST_VERSION:()=>1,buildAssets:()=>m});async function m(e,t){let{cwd:n,silent:i=!1}=t,o=t.distDir??e?.build?.outDir??`dist`,s=e?.assetMap;if(!s||Object.keys(s).length===0)return null;let d=i?()=>{}:console.log,f=u(n,o);r(f,{recursive:!0});let p=[],m={};for(let[e,t]of Object.entries(s)){let r=await h(e,t,n,f);p.push(r.entrySummary),Object.assign(m,r.manifestSlice),d(` ✓ ${e}: ${r.entrySummary.filesCopied} file(s) → ${r.entrySummary.dest}`)}let g={version:1,entries:m},_=c(f,`.kickjs-assets.json`);return a(_,JSON.stringify(g,null,2)+`
12
12
  `,`utf-8`),d(` ✓ wrote manifest → ${l(n,_)} (${Object.keys(m).length} entries)`),{manifestPath:_,entries:p,manifest:g}}async function h(e,i,a,s){let p=u(a,i.src),m=i.dest?u(a,i.dest):c(s,e);if(v(m,a))return console.warn(` ⚠ assetMap.${e}.dest ('${i.dest}') resolves outside the project root — skipping copy`),{entrySummary:{namespace:e,src:i.src,dest:l(a,m),filesCopied:0},manifestSlice:{}};if(!n(p)||!y(p))return{entrySummary:{namespace:e,src:i.src,dest:l(a,m),filesCopied:0},manifestSlice:{}};let h=await d(i.glob??`**/*`,{cwd:p,nodir:!0,dot:!1,posix:!0});r(m,{recursive:!0});let b={},{pairs:x,collisionGroupsResolved:S}=f(e,[...h].toSorted(),{strategy:i.keys??`auto`}),C=0;for(let{rel:e,key:n}of x){let i=c(p,e),a=c(m,e);b[n]=_(s,a),!g(i,a)&&(r(o(a),{recursive:!0}),t(i,a),C++)}return S>0&&console.log(` ℹ assetMap.${e}: auto-resolved ${S} 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:i.src,dest:l(a,m),filesCopied:C},manifestSlice:b}}function g(e,t){if(!n(t))return!1;try{let n=i(e),r=i(t);return r.size===n.size&&r.mtimeMs>=n.mtimeMs}catch{return!1}}function _(e,t){return l(e,t).split(/[\\/]/).filter(Boolean).join(`/`)}function v(e,t){let n=l(t,e);return n===``?!1:n.startsWith(`..`)||s(n)}function y(e){try{return i(e).isDirectory()}catch{return!1}}export{p as n,m as t};
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs-cli v8.1.5
2
+ * @forinda/kickjs-cli v8.1.6
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,4 +8,4 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{t as e}from"./run-plugins-BKWupYoJ.mjs";export{e as builtinCliPlugins};
11
+ import{t as e}from"./run-plugins-GxEtP9WR.mjs";export{e as builtinCliPlugins};
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs-cli v8.1.5
2
+ * @forinda/kickjs-cli v8.1.6
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{t as e}from"./rolldown-runtime-DmTqmRjS.mjs";import{a as t,c as n,i as r,o as i,r as a,s as o,t as s,u as c}from"./project-DfBzpCeE.mjs";import{a as l,c as u,i as d,l as f,o as p,r as m,s as h}from"./config-CzL24fBQ.mjs";import{n as g,r as _}from"./plugin-BSNGbECd.mjs";import{c as v,l as y,s as b}from"./project-docs-DRLN1EDX.mjs";import{a as x,c as S,d as ee,f as C,i as te,l as ne,n as re,o as ie,p as ae,r as w,s as T,u as oe}from"./agent-docs-BK33p0Pw.mjs";import{t as E}from"./project-root-BsyQhlS5.mjs";import{_ as se,a as ce,c as le,d as ue,f as de,g as fe,h as pe,i as me,l as he,m as ge,o as _e,p as ve,r as ye,s as be,t as xe,u as Se}from"./typegen-B6vIx4Qd.mjs";import{t as Ce}from"./build-clh7HpZV.mjs";import{createRequire as we}from"node:module";import{cpSync as Te,existsSync as D,mkdirSync as Ee,readFileSync as O,readdirSync as k,rmSync as De,statSync as Oe,writeFileSync as ke}from"node:fs";import A,{basename as Ae,dirname as j,join as M,relative as N,resolve as P,sep as je}from"node:path";import{fileURLToPath as Me,pathToFileURL as F}from"node:url";import{fork as Ne,spawn as Pe,spawnSync as Fe}from"node:child_process";import{copyFile as Ie,mkdir as Le,readFile as I,readdir as Re,rm as ze,stat as Be,writeFile as L}from"node:fs/promises";import"@forinda/kickjs-cli-kit";import Ve from"pluralize";import{arch as He,platform as Ue,release as We}from"node:os";import{createHash as Ge}from"node:crypto";const Ke=[{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 qe(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 | fullstack`).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. swagger,ws,queue,devtools)`).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)=>{te(`KickJS — Create a new project`);let r=!!(t.yes||t.nonInteractive);e||=r?`my-api`:await oe({message:`Project name`,placeholder:`my-api`,defaultValue:`my-api`});let i;if(e===`.`?(i=P(`.`),e=Ae(i)):i=P(t.directory||e),D(i)){let n=k(i);if(n.length>0){if(t.force)x.warn(`Clearing existing files in ${i}`);else if(r){x.warn(`Directory "${e}" is not empty. Pass --force to clear it.`),T(`Aborted.`);return}else{x.warn(`Directory "${e}" is not empty:`);let t=n.slice(0,5);for(let e of t)x.message(` - ${e}`);if(n.length>5&&x.message(` ... and ${n.length-5} more`),!await w({message:C.red(`Remove all existing files and proceed?`),initialValue:!1})){T(`Aborted.`);return}}for(let e of n)De(P(i,e),{recursive:!0,force:!0})}}let a=t.template;a||=r?`minimal`:await S({message:`Project template`,options:[{value:`rest`,label:`REST API`,hint:`Express + Swagger`},{value:`minimal`,label:`Minimal`,hint:`bare Express`},{value:`fullstack`,label:`Fullstack`,hint:`server + Vite React web, typed client`}]});let o=t.runtime;o||=r?`express`:await S({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 c=t.pm;c||=r?await n(void 0):await S({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||=r?`inmemory`:await oe({message:`Repository name`,placeholder:`inmemory (or a DB name, e.g. postgres)`,defaultValue:`inmemory`}),f(l);let u=t.schema;u||=r?`zod`:await S({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)||(x.warn(`Unknown --schema "${u}", falling back to zod.`),u=`zod`);let d;if(t.packages!==void 0){let e=t.packages.trim().toLowerCase();d=e===``||e===`none`||e===`false`?[]:t.packages.split(`,`).map(e=>e.trim()).filter(Boolean)}else d=r?[]:await ie({message:`Select packages to include`,options:[...Ke],required:!1});let p;p=t.git===void 0?r?!0:await w({message:`Initialize git repository?`,initialValue:!0}):t.git;let m;if(m=t.install===void 0?r?!0:await w({message:`Install dependencies?`,initialValue:!0}):t.install,a===`fullstack`){let{initFullstackProject:t}=await import(`./fullstack-DAEEITND.mjs`);await t({name:e,directory:i,packageManager:c,initGit:p,installDeps:m,schemaLib:u,runtime:o}),T(`Done! Next steps: ${C.cyan(`cd ${e} && ${c}${c===`pnpm`?` dev`:` run dev:server`}`)}`);return}await s({name:e,directory:i,packageManager:c,initGit:p,installDeps:m,template:a,defaultRepo:l,packages:d,schemaLib:u,runtime:o}),T(`Done! Next steps: ${C.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 Ve.plural(e)}function Je(e){return Ve.plural(e)}function Ye(e){return B(e).replace(/-/g,`_`)}function Xe(e){let t=e.cwd??process.cwd(),n=e.projectRoot??E(t),r=e.pluralize??!0,i=R(e.name),a=z(e.name),o=B(e.name),s=Ye(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 Ze(e,t){return P(e.cwd,t)}async function Qe(e){return import(F(e).href)}const $e=new Map;async function et(e){let t=$e.get(e);if(t)return t;let n=tt(e);return $e.set(e,n),n}async function tt(e){let t=P(e,`package.json`);if(!D(t))return{generators:[],loaded:[],failed:[]};let n=nt(JSON.parse(await I(t,`utf-8`))),r=we(P(e,`package.json`)),i=[],a=[],o=[];for(let e of n){let t;try{t=r.resolve(`${e}/package.json`)}catch{continue}let n;try{n=JSON.parse(await I(t,`utf-8`))}catch(t){o.push({source:e,reason:`failed to parse package.json: ${t}`});continue}if(!n.kickjs?.generators)continue;let s=n.kickjs.generators,c=P(j(t),s);if(!D(c)){o.push({source:e,reason:`kickjs.generators points to missing file: ${s}`});continue}let l;try{l=await Qe(c)}catch(t){o.push({source:e,reason:`failed to import manifest: ${t}`});continue}let u=l.default;if(!Array.isArray(u)){o.push({source:e,reason:`manifest's default export is not an array of GeneratorSpec`});continue}for(let t of u){if(!rt(t)){o.push({source:e,reason:`manifest entry is not a valid GeneratorSpec (missing name/files)`});continue}i.push({source:e,spec:t})}a.push(e)}return{generators:i,loaded:a,failed:o}}function nt(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 rt(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function it(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return st(r.spec,r.source,e,n);let i=ot(await et(n),e.generatorName);return i?st(i.spec,i.source,e,n):null}async function at(e,t=[]){let n=await et(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 ot(e,t){return e.generators.find(e=>e.spec.name===t)}async function st(e,t,n,r){let i=Xe({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=Ze(i,e.path);await y(t,e.content),o.push(t)}return{files:o,source:t}}function H(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}const ct={inmemory:`in-memory`,drizzle:`Drizzle`,prisma:`Prisma`};function lt(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function ut(e){return ct[e]??lt(e)}function dt(e){return`create${e}Repository`}function ft(e){return e??`define`}function pt(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,o=dt(t),s=ft(a),c=`/**
11
+ import{t as e}from"./rolldown-runtime-D-i_dFAb.mjs";import{a as t,c as n,i as r,o as i,r as a,s as o,t as s,u as c}from"./project-5ljMCm0U.mjs";import{a as l,c as u,i as d,l as f,o as p,r as m,s as h}from"./config-BYSNxf_t.mjs";import{n as g,r as _}from"./plugin-IEDGa0ny.mjs";import{c as v,l as y,s as b}from"./project-docs-CYCi7cHt.mjs";import{a as x,c as S,d as ee,f as C,i as te,l as ne,n as re,o as ie,p as ae,r as w,s as T,u as oe}from"./agent-docs-BBlVl1tY.mjs";import{t as E}from"./project-root-BhBKSGeK.mjs";import{_ as se,a as ce,c as le,d as ue,f as de,g as fe,h as pe,i as me,l as he,m as ge,o as _e,p as ve,r as ye,s as be,t as xe,u as Se}from"./typegen-D7aeVM0D.mjs";import{t as Ce}from"./build-htBdOg51.mjs";import{createRequire as we}from"node:module";import{cpSync as Te,existsSync as D,mkdirSync as Ee,readFileSync as O,readdirSync as k,rmSync as De,statSync as Oe,writeFileSync as ke}from"node:fs";import A,{basename as Ae,dirname as j,join as M,relative as N,resolve as P,sep as je}from"node:path";import{fileURLToPath as Me,pathToFileURL as F}from"node:url";import{fork as Ne,spawn as Pe,spawnSync as Fe}from"node:child_process";import{copyFile as Ie,mkdir as Le,readFile as I,readdir as Re,rm as ze,stat as Be,writeFile as L}from"node:fs/promises";import"@forinda/kickjs-cli-kit";import Ve from"pluralize";import{arch as He,platform as Ue,release as We}from"node:os";import{createHash as Ge}from"node:crypto";const Ke=[{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 qe(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 | fullstack`).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. swagger,ws,queue,devtools)`).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)=>{te(`KickJS — Create a new project`);let r=!!(t.yes||t.nonInteractive);e||=r?`my-api`:await oe({message:`Project name`,placeholder:`my-api`,defaultValue:`my-api`});let i;if(e===`.`?(i=P(`.`),e=Ae(i)):i=P(t.directory||e),D(i)){let n=k(i);if(n.length>0){if(t.force)x.warn(`Clearing existing files in ${i}`);else if(r){x.warn(`Directory "${e}" is not empty. Pass --force to clear it.`),T(`Aborted.`);return}else{x.warn(`Directory "${e}" is not empty:`);let t=n.slice(0,5);for(let e of t)x.message(` - ${e}`);if(n.length>5&&x.message(` ... and ${n.length-5} more`),!await w({message:C.red(`Remove all existing files and proceed?`),initialValue:!1})){T(`Aborted.`);return}}for(let e of n)De(P(i,e),{recursive:!0,force:!0})}}let a=t.template;a||=r?`minimal`:await S({message:`Project template`,options:[{value:`rest`,label:`REST API`,hint:`Express + Swagger`},{value:`minimal`,label:`Minimal`,hint:`bare Express`},{value:`fullstack`,label:`Fullstack`,hint:`server + Vite React web, typed client`}]});let o=t.runtime;o||=r?`express`:await S({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 c=t.pm;c||=r?await n(void 0):await S({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||=r?`inmemory`:await oe({message:`Repository name`,placeholder:`inmemory (or a DB name, e.g. postgres)`,defaultValue:`inmemory`}),f(l);let u=t.schema;u||=r?`zod`:await S({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)||(x.warn(`Unknown --schema "${u}", falling back to zod.`),u=`zod`);let d;if(t.packages!==void 0){let e=t.packages.trim().toLowerCase();d=e===``||e===`none`||e===`false`?[]:t.packages.split(`,`).map(e=>e.trim()).filter(Boolean)}else d=r?[]:await ie({message:`Select packages to include`,options:[...Ke],required:!1});let p;p=t.git===void 0?r?!0:await w({message:`Initialize git repository?`,initialValue:!0}):t.git;let m;if(m=t.install===void 0?r?!0:await w({message:`Install dependencies?`,initialValue:!0}):t.install,a===`fullstack`){let{initFullstackProject:t}=await import(`./fullstack-19gafr4U.mjs`);await t({name:e,directory:i,packageManager:c,initGit:p,installDeps:m,schemaLib:u,runtime:o}),T(`Done! Next steps: ${C.cyan(`cd ${e} && ${c}${c===`pnpm`?` dev`:` run dev:server`}`)}`);return}await s({name:e,directory:i,packageManager:c,initGit:p,installDeps:m,template:a,defaultRepo:l,packages:d,schemaLib:u,runtime:o}),T(`Done! Next steps: ${C.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 Ve.plural(e)}function Je(e){return Ve.plural(e)}function Ye(e){return B(e).replace(/-/g,`_`)}function Xe(e){let t=e.cwd??process.cwd(),n=e.projectRoot??E(t),r=e.pluralize??!0,i=R(e.name),a=z(e.name),o=B(e.name),s=Ye(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 Ze(e,t){return P(e.cwd,t)}async function Qe(e){return import(F(e).href)}const $e=new Map;async function et(e){let t=$e.get(e);if(t)return t;let n=tt(e);return $e.set(e,n),n}async function tt(e){let t=P(e,`package.json`);if(!D(t))return{generators:[],loaded:[],failed:[]};let n=nt(JSON.parse(await I(t,`utf-8`))),r=we(P(e,`package.json`)),i=[],a=[],o=[];for(let e of n){let t;try{t=r.resolve(`${e}/package.json`)}catch{continue}let n;try{n=JSON.parse(await I(t,`utf-8`))}catch(t){o.push({source:e,reason:`failed to parse package.json: ${t}`});continue}if(!n.kickjs?.generators)continue;let s=n.kickjs.generators,c=P(j(t),s);if(!D(c)){o.push({source:e,reason:`kickjs.generators points to missing file: ${s}`});continue}let l;try{l=await Qe(c)}catch(t){o.push({source:e,reason:`failed to import manifest: ${t}`});continue}let u=l.default;if(!Array.isArray(u)){o.push({source:e,reason:`manifest's default export is not an array of GeneratorSpec`});continue}for(let t of u){if(!rt(t)){o.push({source:e,reason:`manifest entry is not a valid GeneratorSpec (missing name/files)`});continue}i.push({source:e,spec:t})}a.push(e)}return{generators:i,loaded:a,failed:o}}function nt(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 rt(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function it(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return st(r.spec,r.source,e,n);let i=ot(await et(n),e.generatorName);return i?st(i.spec,i.source,e,n):null}async function at(e,t=[]){let n=await et(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 ot(e,t){return e.generators.find(e=>e.spec.name===t)}async function st(e,t,n,r){let i=Xe({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=Ze(i,e.path);await y(t,e.content),o.push(t)}return{files:o,source:t}}function H(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}const ct={inmemory:`in-memory`,drizzle:`Drizzle`,prisma:`Prisma`};function lt(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function ut(e){return ct[e]??lt(e)}function dt(e){return`create${e}Repository`}function ft(e){return e??`define`}function pt(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,o=dt(t),s=ft(a),c=`/**
12
12
  * ${t} Module
13
13
  *
14
14
  * REST module with a flat folder structure.
@@ -1290,7 +1290,7 @@ describe('${o}', () => {
1290
1290
  Example: kick g scaffold Post title:string body:text:optional published:boolean:optional
1291
1291
  Optional: append :optional (shell-safe, no quoting needed)
1292
1292
  `),process.exit(1));let a=await l(process.cwd()),o=p(a),s=n.modulesDir??o.dir??`src/modules`,c=cn(t),f=u(a,process.cwd()),m=d(E()),h=await ln({name:e,fields:c,modulesDir:P(s),noEntity:n.entity===!1,noTests:n.tests===!1,pluralize:n.pluralize===!1?!1:o.pluralize??!0,tokenScope:f,swagger:m,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)`:``}`);q(h,i),await _n(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=K(t);v(n),q(await qt({outDir:P(`.`),modulesDir:e.modulesDir,defaultRepo:e.repo,force:e.force}),n)}),n.command(`agents`).alias(`agent-docs`).alias(`ai-docs`).description(`Regenerate .agents/* + root CLAUDE.md (sync after framework upgrades)`).option(`--only <which>`,`Limit scope: agents | claude | skills | gemini | copilot | 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 | fullstack`).option(`-f, --force`,`Overwrite existing files without prompting`).action(async(e,t)=>{let n=K(t);v(n);let r=e.only??`all`;if(!gn.includes(r)){console.error(` Invalid --only value: ${r}. Expected: ${gn.join(` | `)}`),process.exitCode=1;return}q(await re({outDir:P(`.`),only:r,name:e.name,pm:e.pm,template:e.template,force:e.force}),n)});for(let e of t?.generators??[])wn(n,e,t?.projectRoot)}function wn(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=K(o);v(s);let c=await it({generatorName:i.name,itemName:e??``,args:r??[],flags:a,cwd:process.cwd(),projectRoot:n},[t]);c&&q(c.files,s)})}const Tn=`/* AUTO-GENERATED by kick typegen — do not edit. Plugin: `;async function En(e){let t=A.resolve(e.cwd,`.kickjs/types`);e.check||await Le(t,{recursive:!0});let n=new Map,r=e.scan??fe,i=A.resolve(e.cwd,`.kickjs`,`cache`),a=e.scan?void 0:e.changedFiles,o={cwd:e.cwd,config:e.config,async importTs(e){return await import(F(e).href)},async writeFile(t,n){let r=A.resolve(e.cwd,t);await Le(A.dirname(r),{recursive:!0}),await L(r,n,`utf8`)},getScanResult:e=>{let t=Dn(e),o=n.get(t);if(!o){let s={cacheDir:i,...e};o=a?se(s,a):r(s),n.set(t,o)}return o},log:console,watch:e.watch,check:e.check},s=[],c=[];for(let n of e.plugins){let r=n.outExtension??`.d.ts`,i=A.join(t,`${n.id.replace(/\//g,`__`)}${r}`),a;try{a=await n.generate(o)}catch(t){let r=t instanceof Error?t.message:String(t);if(e.check)throw Error(`kick typegen --check: ${n.id} failed to generate (${r})`,{cause:t});o.log.error(` ${n.id}: typegen failed (${r}) — keeping previous output`),s.push({id:n.id,status:`error`,outFile:i});continue}if(a===null){s.push({id:n.id,status:`skipped`});continue}let l=`${Tn}${n.id} */\n\n`+a+`
1293
- `,u=``;if(D(i)&&(u=await I(i,`utf8`)),u===l){s.push({id:n.id,status:`unchanged`,outFile:i});continue}if(e.check){c.push({id:n.id,outFile:i}),s.push({id:n.id,status:`drifted`,outFile:i});continue}await L(i,l,`utf8`),s.push({id:n.id,status:`written`,outFile:i})}if(c.length>0)throw new hn(c);return s}function Dn(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 On(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 kn=e({applyDisableFilter:()=>On,runAllPluginTypegens:()=>An});async function An(e){let{enabled:t,skipped:n,unknown:r}=On(g([...Fa,...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 En({cwd:e.cwd,config:e.config??{},plugins:t,watch:e.watch,check:e.check,changedFiles:e.changedFiles});if(!e.silent&&mn())for(let e of n)console.log(` ${e.id}: ${e.status}`);return n}catch(t){if(t instanceof hn||e.check)throw t;if(!e.silent){let e=t instanceof Error?t.message:String(t);console.warn(` kick typegen plugins: skipped (${e})`)}return[]}}function jn(e){let t=new Map;return{report(n,r){let i=r instanceof Error?r.message:String(r);t.get(n)!==i&&(t.set(n,i),e(` kick typegen: ${n} pass failed (${i}) — types in .kickjs/types may be stale`))},clear(e){t.delete(e)}}}function Mn(e){let{cwd:t,config:n}=e,r=e.debounceMs??100,i=e.pipeline??{runTypegen:async e=>(await import(`./typegen-B6vIx4Qd.mjs`).then(e=>e.n)).runTypegen(e),runAllPluginTypegens:async e=>(await Promise.resolve().then(()=>kn)).runAllPluginTypegens(e),writeTypegenArtifacts:async(e,t,n)=>(await import(`./typegen-B6vIx4Qd.mjs`).then(e=>e.n)).writeTypegenArtifacts(e,t,n),buildAssets:async(e,t)=>(await import(`./build-clh7HpZV.mjs`).then(e=>e.n)).buildAssets(e,t)},a=n?.typegen?.schemaValidator??`zod`,o=n?.typegen?.envFile,s=A.resolve(t,n?.typegen?.outDir??`.kickjs/types`),c=n?.assetMap?Object.values(n.assetMap).map(e=>e?.src).filter(e=>typeof e==`string`&&e.length>0).map(e=>A.resolve(t,e)):[],l=!!n?.assetMap&&Object.keys(n.assetMap).length>0,u=e=>e.replaceAll(`\\`,`/`),d=c.map(u),f=e=>{let t=u(e);return d.some(e=>t===e||t.startsWith(`${e}/`))},p=jn(e.emitWarning),m=null,h=!1,g=new Set,_=new Set,v=!1,y=!1;function b(r,c){i.runTypegen({cwd:t,silent:!0,allowDuplicates:!0,schemaValidator:a,envFile:o,srcDir:n?.typegen?.srcDir,outDir:n?.typegen?.outDir,assetMap:n?.assetMap,changedFiles:r,runPlugins:!1}).then(()=>p.clear(`scan`)).catch(e=>p.report(`scan`,e)),i.runAllPluginTypegens({cwd:t,config:n,silent:!0,changedFiles:r,watch:!0}).then(e=>i.writeTypegenArtifacts(s,e,!0)).then(()=>p.clear(`plugins`)).catch(e=>p.report(`plugins`,e)).finally(()=>e.onPassComplete?.()),c&&n&&i.buildAssets(n,{cwd:t,silent:!0}).catch(()=>{})}function x(){let e=v?void 0:{changed:[...g],removed:[..._]},t=y;g.clear(),_.clear(),v=!1,y=!1,b(e,t)}return{assetSrcRoots:c,handleWatchEvent(e,t){if(!h&&!u(t).includes(`/.kickjs/`)){if(e===`unlinkDir`)v=!0,l&&(y=!0);else{if(t.endsWith(`.d.ts`))return;let n=/\.(ts|tsx|mts|cts)$/.test(t),r=f(t);if(!n&&!r)return;r&&l&&(y=!0),n&&(e===`unlink`?(_.add(t),g.delete(t)):(g.add(t),_.delete(t)))}m&&clearTimeout(m),m=setTimeout(x,r)}},runOnce(){h||b(void 0,l)},dispose(){h=!0,m&&clearTimeout(m),m=null}}}function Nn(e){let t=M(e,`node_modules`,`.bin`),n=process.platform===`win32`;for(let e of[`vue-tsc`,`tsgo`,`tsc`]){let r=n?[`${e}.CMD`,`${e}.cmd`,`${e}.exe`]:[e];for(let i of r){let r=M(t,i);if(D(r))return{cmd:r,args:[`--noEmit`],shell:n,kind:e}}}return null}function Pn(e){let t=e.spawnFn??Pe,n=null,r=0,i=!1;return{schedule(){if(i)return;let a=++r;n&&=(n.kill(),null);let o=Date.now(),s=t(e.bin.cmd,e.bin.args,{cwd:e.cwd,shell:e.bin.shell,stdio:[`ignore`,`pipe`,`pipe`]});n=s;let c=``;s.stdout?.on(`data`,e=>{c+=e.toString()}),s.stderr?.on(`data`,e=>{c+=e.toString()}),s.on(`error`,()=>{a===r&&(n=null)}),s.on(`close`,t=>{i||a!==r||(n=null,e.onResult({ok:t===0,output:c,durationMs:Date.now()-o,kind:e.bin.kind}))})},dispose(){i=!0,n&&=(n.kill(),null)}}}function Fn(e,t=12){let n=e.trim().split(/\r?\n/);return n.length<=t?n.join(`
1293
+ `,u=``;if(D(i)&&(u=await I(i,`utf8`)),u===l){s.push({id:n.id,status:`unchanged`,outFile:i});continue}if(e.check){c.push({id:n.id,outFile:i}),s.push({id:n.id,status:`drifted`,outFile:i});continue}await L(i,l,`utf8`),s.push({id:n.id,status:`written`,outFile:i})}if(c.length>0)throw new hn(c);return s}function Dn(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 On(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 kn=e({applyDisableFilter:()=>On,runAllPluginTypegens:()=>An});async function An(e){let{enabled:t,skipped:n,unknown:r}=On(g([...Fa,...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 En({cwd:e.cwd,config:e.config??{},plugins:t,watch:e.watch,check:e.check,changedFiles:e.changedFiles});if(!e.silent&&mn())for(let e of n)console.log(` ${e.id}: ${e.status}`);return n}catch(t){if(t instanceof hn||e.check)throw t;if(!e.silent){let e=t instanceof Error?t.message:String(t);console.warn(` kick typegen plugins: skipped (${e})`)}return[]}}function jn(e){let t=new Map;return{report(n,r){let i=r instanceof Error?r.message:String(r);t.get(n)!==i&&(t.set(n,i),e(` kick typegen: ${n} pass failed (${i}) — types in .kickjs/types may be stale`))},clear(e){t.delete(e)}}}function Mn(e){let{cwd:t,config:n}=e,r=e.debounceMs??100,i=e.pipeline??{runTypegen:async e=>(await import(`./typegen-D7aeVM0D.mjs`).then(e=>e.n)).runTypegen(e),runAllPluginTypegens:async e=>(await Promise.resolve().then(()=>kn)).runAllPluginTypegens(e),writeTypegenArtifacts:async(e,t,n)=>(await import(`./typegen-D7aeVM0D.mjs`).then(e=>e.n)).writeTypegenArtifacts(e,t,n),buildAssets:async(e,t)=>(await import(`./build-htBdOg51.mjs`).then(e=>e.n)).buildAssets(e,t)},a=n?.typegen?.schemaValidator??`zod`,o=n?.typegen?.envFile,s=A.resolve(t,n?.typegen?.outDir??`.kickjs/types`),c=n?.assetMap?Object.values(n.assetMap).map(e=>e?.src).filter(e=>typeof e==`string`&&e.length>0).map(e=>A.resolve(t,e)):[],l=!!n?.assetMap&&Object.keys(n.assetMap).length>0,u=e=>e.replaceAll(`\\`,`/`),d=c.map(u),f=e=>{let t=u(e);return d.some(e=>t===e||t.startsWith(`${e}/`))},p=jn(e.emitWarning),m=null,h=!1,g=new Set,_=new Set,v=!1,y=!1;function b(r,c){i.runTypegen({cwd:t,silent:!0,allowDuplicates:!0,schemaValidator:a,envFile:o,srcDir:n?.typegen?.srcDir,outDir:n?.typegen?.outDir,assetMap:n?.assetMap,changedFiles:r,runPlugins:!1}).then(()=>p.clear(`scan`)).catch(e=>p.report(`scan`,e)),i.runAllPluginTypegens({cwd:t,config:n,silent:!0,changedFiles:r,watch:!0}).then(e=>i.writeTypegenArtifacts(s,e,!0)).then(()=>p.clear(`plugins`)).catch(e=>p.report(`plugins`,e)).finally(()=>e.onPassComplete?.()),c&&n&&i.buildAssets(n,{cwd:t,silent:!0}).catch(()=>{})}function x(){let e=v?void 0:{changed:[...g],removed:[..._]},t=y;g.clear(),_.clear(),v=!1,y=!1,b(e,t)}return{assetSrcRoots:c,handleWatchEvent(e,t){if(!h&&!u(t).includes(`/.kickjs/`)){if(e===`unlinkDir`)v=!0,l&&(y=!0);else{if(t.endsWith(`.d.ts`))return;let n=/\.(ts|tsx|mts|cts)$/.test(t),r=f(t);if(!n&&!r)return;r&&l&&(y=!0),n&&(e===`unlink`?(_.add(t),g.delete(t)):(g.add(t),_.delete(t)))}m&&clearTimeout(m),m=setTimeout(x,r)}},runOnce(){h||b(void 0,l)},dispose(){h=!0,m&&clearTimeout(m),m=null}}}function Nn(e){let t=M(e,`node_modules`,`.bin`),n=process.platform===`win32`;for(let e of[`vue-tsc`,`tsgo`,`tsc`]){let r=n?[`${e}.CMD`,`${e}.cmd`,`${e}.exe`]:[e];for(let i of r){let r=M(t,i);if(D(r))return{cmd:r,args:[`--noEmit`],shell:n,kind:e}}}return null}function Pn(e){let t=e.spawnFn??Pe,n=null,r=0,i=!1;return{schedule(){if(i)return;let a=++r;n&&=(n.kill(),null);let o=Date.now(),s=t(e.bin.cmd,e.bin.args,{cwd:e.cwd,shell:e.bin.shell,stdio:[`ignore`,`pipe`,`pipe`]});n=s;let c=``;s.stdout?.on(`data`,e=>{c+=e.toString()}),s.stderr?.on(`data`,e=>{c+=e.toString()}),s.on(`error`,()=>{a===r&&(n=null)}),s.on(`close`,t=>{i||a!==r||(n=null,e.onResult({ok:t===0,output:c,durationMs:Date.now()-o,kind:e.bin.kind}))})},dispose(){i=!0,n&&=(n.kill(),null)}}}function Fn(e,t=12){let n=e.trim().split(/\r?\n/);return n.length<=t?n.join(`
1294
1294
  `):`${n.slice(0,t).join(`
1295
1295
  `)}\n… ${n.length-t} more line(s)`}function In(e){if(typeof e==`boolean`)return e;let t=process.env.KICKJS_WATCH_POLLING;return t===`1`||t===`true`}async function Ln(e,t=`127.0.0.1`){let n=await import(`node:inspector`);n.open(e,t,!1);let r=n.url();if(!r)throw Error(`inspector.open() reported no URL`);return r}async function Rn(e,t,n={}){t&&(process.env.PORT=t);let r=In(n.polling),i=process.cwd(),a=await l(i),o=a?.typegen?.schemaValidator??`zod`,s=a?.typegen?.envFile;try{await xe({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=P(i,a?.typegen?.outDir??`.kickjs/types`);try{await me(c,await An({cwd:i,config:a}),!1)}catch(e){console.warn(` kick typegen: plugin pass skipped (${e?.message??e})`)}let{createRequire:u}=await import(`node:module`),{createServer:d}=await import(F(u(P(`package.json`)).resolve(`vite`)).href);globalThis.__kickjs_typegen_owner=`kick-dev`;let f=await d({configFile:P(`vite.config.ts`),server:{port:t?parseInt(t,10):void 0,...r?{watch:{usePolling:!0,interval:100}}:{}}}),p=n.typecheck??a?.dev?.typecheck??!1,m=null,h=!0;if(p){let e=Nn(i);e?m=Pn({cwd:i,bin:e,onResult:e=>{f.hot.send({type:`custom`,event:`kickjs:typecheck`,data:{ok:e.ok,output:e.output,durationMs:e.durationMs}}),e.ok?h||(h=!0,console.log(` kick typecheck: clean again (${e.kind}, ${e.durationMs}ms)`)):(h=!1,console.warn(`\n kick typecheck (${e.kind}, ${e.durationMs}ms):`),console.warn(Fn(e.output).replace(/^/gm,` `)))}}):console.warn(` kick dev: --typecheck requested but neither tsgo (@typescript/native-preview) nor typescript is installed in this project — skipping type checks.`)}let g=Mn({cwd:i,config:a,emitWarning:e=>{console.warn(e),f.hot.send({type:`custom`,event:`kickjs:typegen-error`,data:{message:e,timestamp:Date.now()}})},onPassComplete:()=>m?.schedule()});f.watcher.on(`add`,e=>g.handleWatchEvent(`add`,e)),f.watcher.on(`unlink`,e=>g.handleWatchEvent(`unlink`,e)),f.watcher.on(`change`,e=>g.handleWatchEvent(`change`,e)),f.watcher.on(`unlinkDir`,e=>g.handleWatchEvent(`unlinkDir`,e)),g.assetSrcRoots.length>0&&f.watcher.add([...g.assetSrcRoots]),await f.listen(),f.printUrls(),console.log(`
1296
1296
  KickJS dev server running (Vite + @forinda/kickjs-vite)
@@ -1313,7 +1313,7 @@ describe('${o}', () => {
1313
1313
  pnpm add -D @typescript/native-preview (tsgo, faster)
1314
1314
  `),process.exit(1);return}let r=Fe(n.cmd,n.args,{stdio:`inherit`,shell:n.shell,cwd:t});process.exit(r.status??1)}),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`).option(`--inspect-host <host>`,`Inspector bind address (use 0.0.0.0 to reach it from outside a container)`,`127.0.0.1`).action(async e=>{let t=Number(e.inspectPort??`9229`),n=e.inspectHost??`127.0.0.1`;[`127.0.0.1`,`localhost`,`::1`].includes(n)||console.warn(` WARNING: the debugger is bound to ${n}, not loopback. Anyone who can\n reach port ${t} can run code in this process. Use it on a trusted\n network only, and prefer publishing the port from your container instead.`);let r;try{r=await Ln(t,n)}catch(e){console.error(`\n Could not open the inspector on ${t}: ${e.message??e}\n Another process may already hold it — try --inspect-port <port>.`),process.exit(1);return}console.log(` Debugger: ${r}`);try{await Rn(e.entry,e.port)}catch(e){console.error(`
1315
1315
  Dev server (debug) failed:`,e.message??e),process.exit(1)}})}function Vn(){try{let e=j(Me(import.meta.url));return JSON.parse(O(M(e,`..`,`package.json`),`utf-8`)).version??`unknown`}catch{return`unknown`}}const Hn=new Set(Object.values(a).filter(e=>e.deprecated).map(e=>e.pkg));function Un(e){let t=M(e,`package.json`);if(!D(t))return[];let n;try{n=JSON.parse(O(t,`utf-8`))}catch{return[]}let r={...n.dependencies,...n.devDependencies};return Object.keys(r).filter(e=>e===`@forinda/kickjs`||e.startsWith(`@forinda/kickjs-`)).toSorted().map(t=>{let n=null,i=M(e,`node_modules`,...t.split(`/`),`package.json`);if(D(i))try{n=JSON.parse(O(i,`utf-8`)).version??null}catch{}return{name:t,installed:n,declared:r[t]??null,deprecated:Hn.has(t)}})}function Wn(e){let t=e;for(;;){if(D(M(t,`package.json`)))return t;let e=j(t);if(e===t)return null;t=e}}function Gn(e){e.command(`info`).description(`Print system and framework info`).action(()=>{let e=[``,` KickJS CLI v${Vn()}`,``,` System:`,` OS: ${Ue()} ${We()} (${He()})`,` Node: ${process.version}`],t=Wn(process.cwd()),n=t?Un(t):[];if(!t)e.push(``,` Packages: (not inside a project — no package.json found)`);else if(n.length===0)e.push(``,` Packages: (no @forinda/kickjs* dependencies in ${t})`);else{e.push(``,` Packages:`);let t=Math.max(...n.map(e=>e.name.length));for(let r of n){let n=r.installed??`${r.declared??`?`} (declared — not installed)`,i=r.deprecated?" [DEPRECATED — see `kick add --list --all`]":``;e.push(` ${r.name.padEnd(t+2)} ${n}${i}`)}}e.push(``),console.log(e.join(`
1316
- `))})}const{bold:J,dim:Y,green:Kn,red:qn,yellow:Jn,blue:Yn}=C;function Xn(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 Zn(e){let t=await fetch(e,{signal:AbortSignal.timeout(5e3)});if(!t.ok)throw Error(`${t.status} ${t.statusText}`);return t.json()}async function X(e,t){try{return await Zn(`${e}${t}`)}catch{return null}}async function Qn(e){let[t,n,r,i,a]=await Promise.all([X(e,`/health`),X(e,`/metrics`),X(e,`/routes`),X(e,`/container`),X(e,`/ws`)]);return{health:t,metrics:n,routes:r,container:i,ws:a}}function $n(e,t){let{health:n,metrics:r,routes:i,container:a,ws:o}=t,s=Y(`─`.repeat(60));if(console.log(),console.log(J(` KickJS Inspector`)+Y(` → ${e}`)),console.log(s),n){let e=n.status===`healthy`?Kn(`● healthy`):qn(`● `+n.status);console.log(` ${J(`Health:`)} ${e}`)}else console.log(` ${J(`Health:`)} ${qn(`● unreachable`)}`);if(r){let e=((r.errorRate??0)*100).toFixed(1),t=r.errorRate>.1?qn:r.errorRate>0?Jn:Kn;console.log(` ${J(`Uptime:`)} ${Xn(r.uptimeSeconds)}`),console.log(` ${J(`Requests:`)} ${r.requests}`),console.log(` ${J(`Errors:`)} ${r.serverErrors} server, ${r.clientErrors??0} client ${Y(`(`)}${t(e+`%`)}${Y(`)`)}`)}if(a&&console.log(` ${J(`DI:`)} ${a.count} bindings`),o&&o.enabled&&console.log(` ${J(`WS:`)} ${o.connections??0} connections, ${o.namespaces??0} namespaces`),i?.routes?.length){console.log(),console.log(J(` Routes`)),console.log(s),console.log(` ${Y(`METHOD`)} ${Y(`PATH`.padEnd(36))} ${Y(`CONTROLLER`)}`);for(let e of i.routes){let t=e.path.length>36?e.path.slice(0,33)+`...`:e.path.padEnd(36);console.log(` ${ee(e.method)} ${t} ${Yn(e.controller)}.${Y(e.handler)}`)}}console.log(s),console.log()}function er(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 Qn(r);t.json?console.log(JSON.stringify(e,null,2)):$n(n,e)}catch(e){t.json?console.log(JSON.stringify({error:String(e)})):(console.error(qn(` ✖ Could not connect to ${n}`)),console.error(Y(` ${e instanceof Error?e.message:String(e)}`))),t.watch||(process.exitCode=1)}};if(t.watch){let e=async()=>{process.stdout.write(`\x1B[2J\x1B[H`),await i()};await e(),setInterval(e,5e3)}else await i()})}function tr(e,t){let n=e.toLowerCase();return t.every(e=>n.includes(e.toLowerCase()))}function Z(e,t){let n=e.toLowerCase();return t.some(e=>n.includes(e.toLowerCase()))}const nr=[{match(e,t){let n=tr(e,[`config`,`get`])&&Z(e,[`undefined`,`null`]),r=e.includes(`@Value`)&&Z(e,[`undefined`,`is not defined`]);return!n&&!r?null:Z(e,[`vitest`,`createTestApp`,`__tests__`,`.test.`,`.spec.`])?{confidence:85,diagnosis:{id:`env-schema-not-registered-in-test`,title:`ConfigService.get() returns undefined inside a test`,explanation:`The env schema is registered by a module-load side effect in
1316
+ `))})}const{bold:J,dim:Y,green:Kn,red:qn,yellow:Jn,blue:Yn}=C;function Xn(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 Zn(e){let t=await fetch(e,{signal:AbortSignal.timeout(5e3)});if(!t.ok)throw Error(`${t.status} ${t.statusText}`);return t.json()}async function Qn(e,t){try{return await Zn(`${e}${t}`)}catch{return null}}async function $n(e){let[t,n,r,i,a]=await Promise.all([Qn(e,`/health`),Qn(e,`/metrics`),Qn(e,`/routes`),Qn(e,`/container`),Qn(e,`/ws`)]);return{health:t,metrics:n,routes:r,container:i,ws:a}}function er(e,t){let{health:n,metrics:r,routes:i,container:a,ws:o}=t,s=Y(`─`.repeat(60));if(console.log(),console.log(J(` KickJS Inspector`)+Y(` → ${e}`)),console.log(s),n){let e=n.status===`healthy`?Kn(`● healthy`):qn(`● `+n.status);console.log(` ${J(`Health:`)} ${e}`)}else console.log(` ${J(`Health:`)} ${qn(`● unreachable`)}`);if(r){let e=((r.errorRate??0)*100).toFixed(1),t=r.errorRate>.1?qn:r.errorRate>0?Jn:Kn;console.log(` ${J(`Uptime:`)} ${Xn(r.uptimeSeconds)}`),console.log(` ${J(`Requests:`)} ${r.requests}`),console.log(` ${J(`Errors:`)} ${r.serverErrors} server, ${r.clientErrors??0} client ${Y(`(`)}${t(e+`%`)}${Y(`)`)}`)}if(a&&console.log(` ${J(`DI:`)} ${a.count} bindings`),o&&o.enabled&&console.log(` ${J(`WS:`)} ${o.connections??0} connections, ${o.namespaces??0} namespaces`),i?.routes?.length){console.log(),console.log(J(` Routes`)),console.log(s),console.log(` ${Y(`METHOD`)} ${Y(`PATH`.padEnd(36))} ${Y(`CONTROLLER`)}`);for(let e of i.routes){let t=e.path.length>36?e.path.slice(0,33)+`...`:e.path.padEnd(36);console.log(` ${ee(e.method)} ${t} ${Yn(e.controller)}.${Y(e.handler)}`)}}console.log(s),console.log()}function tr(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 $n(r);t.json?console.log(JSON.stringify(e,null,2)):er(n,e)}catch(e){t.json?console.log(JSON.stringify({error:String(e)})):(console.error(qn(` ✖ Could not connect to ${n}`)),console.error(Y(` ${e instanceof Error?e.message:String(e)}`))),t.watch||(process.exitCode=1)}};if(t.watch){let e=async()=>{process.stdout.write(`\x1B[2J\x1B[H`),await i()};await e(),setInterval(e,5e3)}else await i()})}function X(e,t){let n=e.toLowerCase();return t.every(e=>n.includes(e.toLowerCase()))}function Z(e,t){let n=e.toLowerCase();return t.some(e=>n.includes(e.toLowerCase()))}const nr=[{match(e,t){let n=X(e,[`config`,`get`])&&Z(e,[`undefined`,`null`]),r=e.includes(`@Value`)&&Z(e,[`undefined`,`is not defined`]);return!n&&!r?null:Z(e,[`vitest`,`createTestApp`,`__tests__`,`.test.`,`.spec.`])?{confidence:85,diagnosis:{id:`env-schema-not-registered-in-test`,title:`ConfigService.get() returns undefined inside a test`,explanation:`The env schema is registered by a module-load side effect in
1317
1317
  src/config/index.ts, and src/index.ts imports it before bootstrap().
1318
1318
  Tests never load src/index.ts — \`createTestApp\` builds the app
1319
1319
  directly — so that import does not run and ConfigService falls back to
@@ -1347,7 +1347,7 @@ describe('UserController', () => {
1347
1347
  beforeEach(() => Container.reset())
1348
1348
 
1349
1349
  it('does the thing', async () => { /* ... */ })
1350
- })`,docs:`https://kickjs.app/guide/testing.html`}}:null}},{match(e,t){return e.includes(`@Module`)||tr(e,[`Module`,`is not a function`])||tr(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
1350
+ })`,docs:`https://kickjs.app/guide/testing.html`}}:null}},{match(e,t){return e.includes(`@Module`)||X(e,[`Module`,`is not a function`])||X(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
1351
1351
  pattern instead: a class implements AppModule and exposes routes() that
1352
1352
  returns the controller wiring. This was a deliberate choice — modules
1353
1353
  become explicit values rather than metadata, which makes them easier to
@@ -1433,7 +1433,103 @@ beforeAll(() => {
1433
1433
  vi.stubEnv('JWT_SECRET', 'x'.repeat(32))
1434
1434
  resetEnvCache()
1435
1435
  loadEnv(envSchema)
1436
- })`,docs:`https://kickjs.app/guide/testing.html#environment-isolation`}}}}];function rr(e,t){let n=null;for(let r of nr){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 ir(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.
1436
+ })`,docs:`https://kickjs.app/guide/testing.html#environment-isolation`}}}},{match(e,t){let n=X(e,[`cannot inject`,`request-scoped`,`singleton`]),r=X(e,[`request-scoped`,`singleton`]);return!n&&!r?null:{confidence:n?100:70,diagnosis:{id:`di-request-scope-into-singleton`,title:`A SINGLETON cannot hold a REQUEST-scoped dependency`,explanation:`Controllers are SINGLETON by default: one instance for the process, built
1437
+ the first time the container resolves it. A REQUEST-scoped binding is the
1438
+ opposite — one instance per request, discarded when the response ends.
1439
+
1440
+ Injecting the second into the first would capture whichever request
1441
+ happened to build the singleton and hand that same instance to every
1442
+ later request, so the container refuses at resolve time instead.
1443
+
1444
+ This surfaces on the first request that reaches the controller, not at
1445
+ boot, because the container builds lazily. The route mounts fine and then
1446
+ answers 500.`,fix:`The error says "use TRANSIENT or REQUEST scope for the parent", and that
1447
+ is the fix when the parent is a @Service / @Repository / @Component —
1448
+ each takes \`{ scope }\`.
1449
+
1450
+ @Controller() does NOT. It takes no options and always registers as a
1451
+ SINGLETON, so for a controller the advice in the message is not
1452
+ available. Switch that one dependency to @Autowired instead: property
1453
+ injection re-resolves per access, so each request reads its own instance
1454
+ and the singleton never captures one.
1455
+
1456
+ If the dependency did not need request scope in the first place, the
1457
+ other direction also works — make it SINGLETON and pass the per-request
1458
+ values in as method arguments.`,docs:`https://kickjs.app/guide/dependency-injection.html#scopes`}}}},{match(e,t){let n=e.toLowerCase().includes(`circular dependency detected`),r=X(e,[`circular`,`dependency`]);return!n&&!r?null:{confidence:n?100:65,diagnosis:{id:`di-circular-dependency`,title:`Two services depend on each other, directly or through a chain`,explanation:`The container resolves constructor dependencies depth-first. When a token
1459
+ is requested while it is already being resolved further up the stack, the
1460
+ graph has a cycle and there is no order that satisfies both ends.
1461
+
1462
+ The error prints the whole chain, arrow-separated — read it as "A needed
1463
+ B, which needed C, which needed A again". The repeated name at both ends
1464
+ is where the cycle closes, and it is usually the pair in the middle that
1465
+ is worth splitting, not the class you were resolving.
1466
+
1467
+ Constructor injection is what forces the ordering. Property injection
1468
+ (@Autowired) resolves after construction, so it tolerates a cycle the
1469
+ constructor form cannot.`,fix:`Preferred: pull the shared behaviour into a third service both sides
1470
+ depend on. A cycle is usually a missing collaborator, and breaking it
1471
+ this way leaves both classes independently testable.
1472
+
1473
+ If the cycle is genuine and the design is settled, switch ONE side from
1474
+ constructor injection to @Autowired so it resolves lazily.`,codeBefore:`@Service()
1475
+ export class OrderService {
1476
+ constructor(private readonly billing: BillingService) {}
1477
+ }
1478
+
1479
+ @Service()
1480
+ export class BillingService {
1481
+ constructor(private readonly orders: OrderService) {} // ← closes the cycle
1482
+ }`,codeAfter:`@Service()
1483
+ export class OrderService {
1484
+ constructor(private readonly billing: BillingService) {}
1485
+ }
1486
+
1487
+ @Service()
1488
+ export class BillingService {
1489
+ @Autowired() private readonly orders!: OrderService // ← resolved after construction
1490
+ }`,docs:`https://kickjs.app/guide/dependency-injection.html#circular-dependency-detection`}}}},{match(e,t){let n=e.includes(`KICK001`),r=Z(e,[`no provider for`,`no provider found for`,`no binding is registered`]);return!n&&!r?null:{confidence:n?100:85,diagnosis:{id:`di-no-provider-for-token`,title:`A token was requested but nothing registers it`,explanation:`Decorators register bindings as a side effect of the class being LOADED —
1491
+ and a class is only loaded if something imports it. A module that is not
1492
+ in the bootstrap array is never imported, so none of its @Service /
1493
+ @Repository / @Controller classes ever register, and the first thing that
1494
+ asks for one gets this error.
1495
+
1496
+ That makes the failure almost always about the MODULE, not the class the
1497
+ error names — which is why the token in the message usually looks
1498
+ correctly decorated when you open it.
1499
+
1500
+ The other two causes: a class with no decorator at all, or a
1501
+ createToken() handle that nothing binds. Tokens are inert values — they
1502
+ carry a type, never an implementation.`,fix:`Check, in this order:
1503
+ 1. Is the enclosing module in \`bootstrap({ modules })\` (or in the array
1504
+ exported from src/modules/index.ts)?
1505
+ 2. Does the class carry @Service() / @Repository() / @Controller()?
1506
+ 3. For a createToken() token — does some module bind it in \`register()\`?`,codeAfter:`const TENANT_REPO = createToken<TenantRepo>('TENANT_REPO')
1507
+
1508
+ export const TenantModule = defineModule({
1509
+ name: 'TenantModule',
1510
+ build: () => ({
1511
+ register(container) {
1512
+ container.register(TENANT_REPO, { useClass: PrismaTenantRepo }) // ← the binding
1513
+ },
1514
+ routes: () => null,
1515
+ }),
1516
+ })`,docs:`https://kickjs.app/guide/dependency-injection.html#registering-services`}}}},{match(e,t){if(!Z(e,[`vite`,`kick dev`,`dev server`,`localhost:5173`,`:5173`])||!Z(e,[`404`,`not found`,`cannot get`,`cannot post`,`no route`]))return null;let n=X(e,[`app`,`export`]),r=Z(e,[`every route`,`all routes`,`every endpoint`,`all endpoints`,`none of the routes`]);return!n&&!r?null:{confidence:n&&r?85:n?80:70,diagnosis:{id:`vite-dev-app-not-exported`,title:"Every route 404s in dev because the entry file exports no `app`",explanation:`The Vite plugin does not start your server. It imports the entry module
1517
+ and reads \`app\` off it, then hands each request to that instance.
1518
+
1519
+ When the entry runs \`await bootstrap(...)\` without assigning the result to
1520
+ an exported \`app\`, the plugin finds nothing to delegate to and falls
1521
+ through to Vite's own 404 handler. Your app booted; nothing is routing to
1522
+ it.
1523
+
1524
+ The giveaway is that EVERY route 404s, including ones that clearly exist,
1525
+ and the failure is dev-only — \`kick start\` runs the entry directly and
1526
+ never needs the export.`,fix:"Export the bootstrap result as `app` from your entry file. The name is\nload-bearing — the plugin looks up exactly that export.",codeBefore:`import './env'
1527
+ import { bootstrap } from '@forinda/kickjs'
1528
+
1529
+ await bootstrap({ modules }) // ← nothing for the dev server to read`,codeAfter:`import './env'
1530
+ import { bootstrap } from '@forinda/kickjs'
1531
+
1532
+ export const app = await bootstrap({ modules })`,docs:`https://kickjs.app/guide/project-structure.html`}}}}];function rr(e,t){let n=null;for(let r of nr){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 ir(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.
1437
1533
  export OPENAI_API_KEY="sk-..."
1438
1534
 
1439
1535
  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:
@@ -1532,7 +1628,7 @@ server.on('exit', () => {
1532
1628
  Cancelled.
1533
1629
  `);return}await ze(c,{recursive:!0,force:!0}),console.log(` Deleted: ${c}`);let l=M(n,`index.ts`);if(await b(l)){let e=await I(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=kr(e,o),e=e.replace(/\n{3,}/g,`
1534
1630
 
1535
- `),e!==t&&(await L(l,e,`utf-8`),console.log(` Unregistered: ${o}Module from ${l}`))}console.log(`\n Module '${s}' removed.\n`)}function jr(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=p(await l(process.cwd())),r=t.modulesDir??n.dir??`src/modules`,i=t.pluralize===!1?!1:n.pluralize??!0;for(let n of e)await Ar({name:n,modulesDir:P(r),force:t.force,pluralize:i})})}function Mr(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 Nr(e){if(e!==void 0)return e===`false`||e===`off`||e===`none`?!1:e}function Pr(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: exit non-zero if any generated file in .kickjs/types/ is out of date (routes, env, db, assets, adopter plugins) instead of writing it`).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=E(process.cwd()),n=await l(t);if(e.list){let{mergeCliPlugins:e}=await import(`./plugin-BSNGbECd.mjs`).then(e=>e.t),{builtinCliPlugins:t}=await Promise.resolve().then(()=>Pa),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(`
1631
+ `),e!==t&&(await L(l,e,`utf-8`),console.log(` Unregistered: ${o}Module from ${l}`))}console.log(`\n Module '${s}' removed.\n`)}function jr(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=p(await l(process.cwd())),r=t.modulesDir??n.dir??`src/modules`,i=t.pluralize===!1?!1:n.pluralize??!0;for(let n of e)await Ar({name:n,modulesDir:P(r),force:t.force,pluralize:i})})}function Mr(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 Nr(e){if(e!==void 0)return e===`false`||e===`off`||e===`none`?!1:e}function Pr(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: exit non-zero if any generated file in .kickjs/types/ is out of date (routes, env, db, assets, adopter plugins) instead of writing it`).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=E(process.cwd()),n=await l(t);if(e.list){let{mergeCliPlugins:e}=await import(`./plugin-IEDGa0ny.mjs`).then(e=>e.t),{builtinCliPlugins:t}=await Promise.resolve().then(()=>Pa),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(`
1536
1632
  Registered typegen plugins:
1537
1633
  `);for(let e of r.typegens){let t=i.has(e.id)?` (disabled)`:``,n=`${e.id.replace(/\//g,`__`)}${e.outExtension??`.d.ts`}`;console.log(` ${e.id.padEnd(a+2)}→ .kickjs/types/${n}${t}`),console.log(` ${` `.repeat(a+2)} watches: ${e.inputs.join(`, `)||`(none)`}`)}console.log(`
1538
1634
  Disable one in kick.config.ts:
@@ -1700,4 +1796,4 @@ declare global {
1700
1796
 
1701
1797
  export {}
1702
1798
  `}const ba=()=>({id:`kick/env`,outExtension:`.ts`,inputs:[`src/env.ts`,`src/**/env.ts`,`src/**/*.env.ts`],async generate(e){let t=Sa(e);if(t===!1)return null;let n=await e.getScanResult({root:xa(e),cwd:e.cwd,envFile:t});if(!n.env)return null;let r=e.config?.typegen?.schemaValidator??`zod`,i=A.resolve(e.cwd,`.kickjs/types/kick__env.ts`);return ya(n.env,i,r)}});function xa(e){return A.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function Sa(e){return e.config?.typegen?.envFile}function Ca(e){return A.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function wa(e){let t=e.config?.typegen?.envFile;if(t!==!1)return t}function $(e){return{root:Ca(e),cwd:e.cwd,envFile:wa(e)}}const Ta=()=>({id:`kick/registry`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult($(e)),n=A.resolve(e.cwd,`.kickjs/types/kick__registry.d.ts`),r=new Set(t.collisions.map(e=>e.className));return ve(t.classes,n,r)}}),Ea=()=>({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 pe(`ServiceToken`,he(t.classes,t.tokens,t.injects,n),"(no tokens discovered — declare with createToken<T>() or `kick g service <name>`)")}}),Da=()=>({id:`kick/modules`,inputs:[`src/**/*.ts`],async generate(e){return pe(`ModuleToken`,le((await e.getScanResult($(e))).classes),"(no @Module classes discovered — `kick g module <name>` to add one)")}}),Oa=()=>({id:`kick/plugins`,inputs:[`src/**/*.ts`],async generate(e){return de((await e.getScanResult($(e))).pluginsAndAdapters)}}),ka=()=>({id:`kick/augmentations`,inputs:[`src/**/*.ts`],async generate(e){return Se((await e.getScanResult($(e))).augmentations)}}),Aa=()=>({id:`kick/context`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult($(e));return t.contextKeys.length===0?null:ue(t.contextKeys)}}),ja=()=>({id:`kick/route-flags`,inputs:[`src/**/*.ts`],async generate(e){return ge((await e.getScanResult($(e))).routeFlags)}}),Ma={fastify:{subpath:`@forinda/kickjs/fastify`,typeName:`FastifyRuntimeTypes`},h3:{subpath:`@forinda/kickjs/h3`,typeName:`H3RuntimeTypes`}},Na=()=>({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}=Ma[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(`
1703
- `)}});var Pa=e({builtinCliPlugins:()=>Fa});const Fa=[_({name:`kick/init`,register:qe}),_({name:`kick/generate`,register:Cn}),_({name:`kick/run`,register:Bn}),_({name:`kick/info`,register:Gn}),_({name:`kick/inspect`,register:er}),_({name:`kick/add`,register:t}),_({name:`kick/list`,register:i}),_({name:`kick/explain`,register:ur}),_({name:`kick/mcp`,register:xr}),_({name:`kick/tinker`,register:Tr}),_({name:`kick/remove`,register:jr}),_({name:`kick/typegen`,register:Pr}),_({name:`kick/check`,register:Kr}),_({name:`kick/doctor`,register:Ei}),_({name:`kick/codemod`,register:Oi}),_({name:`kick/registry`,typegens:[Ta()]}),_({name:`kick/services`,typegens:[Ea()]}),_({name:`kick/modules`,typegens:[Da()]}),_({name:`kick/plugins`,typegens:[Oa()]}),_({name:`kick/augmentations`,typegens:[ka()]}),_({name:`kick/context`,typegens:[Aa()]}),_({name:`kick/route-flags`,typegens:[ja()]}),_({name:`kick/assets`,typegens:[ki()]}),_({name:`kick/routes`,typegens:[zi()]}),_({name:`kick/client`,typegens:[va()]}),_({name:`kick/env`,typegens:[ba()]}),_({name:`kick/runtime`,typegens:[Na()]})];export{kn as n,Fa as t};
1799
+ `)}});var Pa=e({builtinCliPlugins:()=>Fa});const Fa=[_({name:`kick/init`,register:qe}),_({name:`kick/generate`,register:Cn}),_({name:`kick/run`,register:Bn}),_({name:`kick/info`,register:Gn}),_({name:`kick/inspect`,register:tr}),_({name:`kick/add`,register:t}),_({name:`kick/list`,register:i}),_({name:`kick/explain`,register:ur}),_({name:`kick/mcp`,register:xr}),_({name:`kick/tinker`,register:Tr}),_({name:`kick/remove`,register:jr}),_({name:`kick/typegen`,register:Pr}),_({name:`kick/check`,register:Kr}),_({name:`kick/doctor`,register:Ei}),_({name:`kick/codemod`,register:Oi}),_({name:`kick/registry`,typegens:[Ta()]}),_({name:`kick/services`,typegens:[Ea()]}),_({name:`kick/modules`,typegens:[Da()]}),_({name:`kick/plugins`,typegens:[Oa()]}),_({name:`kick/augmentations`,typegens:[ka()]}),_({name:`kick/context`,typegens:[Aa()]}),_({name:`kick/route-flags`,typegens:[ja()]}),_({name:`kick/assets`,typegens:[ki()]}),_({name:`kick/routes`,typegens:[zi()]}),_({name:`kick/client`,typegens:[va()]}),_({name:`kick/env`,typegens:[ba()]}),_({name:`kick/runtime`,typegens:[Na()]})];export{kn as n,Fa as t};
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs-cli v8.1.5
2
+ * @forinda/kickjs-cli v8.1.6
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,4 +8,4 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{d as e}from"./project-DfBzpCeE.mjs";import{a as t}from"./config-CzL24fBQ.mjs";import{n}from"./plugin-BSNGbECd.mjs";import{t as r}from"./builtins-B6Dc2coA.mjs";import{t as i}from"./project-root-BsyQhlS5.mjs";import{Command as a}from"commander";import{readFileSync as o}from"node:fs";import{delimiter as s,dirname as c,join as l}from"node:path";import{fileURLToPath as u}from"node:url";function d(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}f(e,r)}}function f(t,n){let r=t.command(n.name).description(n.description);if(n.aliases)for(let e of n.aliases)r.alias(e);r.allowUnknownOption(!0),r.argument(`[args...]`,`Additional arguments passed to the command`);function i(){return{PATH:`${l(process.cwd(),`node_modules`,`.bin`)}${s}${process.env.PATH??``}`}}r.action(t=>{let r=t.join(` `),a=Array.isArray(n.steps)?n.steps:[n.steps];for(let t of a){let a=r?`${t} ${r}`:t;console.log(` $ ${a}`);try{e(a,void 0,i())}catch{console.error(` Command failed: ${n.name}`),process.exitCode=1;return}}})}const p=c(u(import.meta.url)),m=JSON.parse(o(l(p,`..`,`package.json`),`utf-8`));async function h(){let e=new a;e.name(`kick`).description(`KickJS — A production-grade, decorator-driven Node.js framework`).version(m.version);let o=i(process.cwd()),s=o,c=await t(s)??{},l=n([...r,...c.plugins??[]],c.commands??[]);await l.register(e,{cwd:s,projectRoot:o,config:c,log:e=>console.log(e)}),d(e,{...c,commands:l.commands}),e.showHelpAfterError();let u=process.argv.map(e=>e===`-v`?`--version`:e);await e.parseAsync(u)}h().catch(e=>{console.error(e instanceof Error?e.message:e),process.exitCode=1});export{};
11
+ import{d as e}from"./project-5ljMCm0U.mjs";import{a as t}from"./config-BYSNxf_t.mjs";import{n}from"./plugin-IEDGa0ny.mjs";import{t as r}from"./builtins-SMK1mtlk.mjs";import{t as i}from"./project-root-BhBKSGeK.mjs";import{Command as a}from"commander";import{readFileSync as o}from"node:fs";import{delimiter as s,dirname as c,join as l}from"node:path";import{fileURLToPath as u}from"node:url";function d(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}f(e,r)}}function f(t,n){let r=t.command(n.name).description(n.description);if(n.aliases)for(let e of n.aliases)r.alias(e);r.allowUnknownOption(!0),r.argument(`[args...]`,`Additional arguments passed to the command`);function i(){return{PATH:`${l(process.cwd(),`node_modules`,`.bin`)}${s}${process.env.PATH??``}`}}r.action(t=>{let r=t.join(` `),a=Array.isArray(n.steps)?n.steps:[n.steps];for(let t of a){let a=r?`${t} ${r}`:t;console.log(` $ ${a}`);try{e(a,void 0,i())}catch{console.error(` Command failed: ${n.name}`),process.exitCode=1;return}}})}const p=c(u(import.meta.url)),m=JSON.parse(o(l(p,`..`,`package.json`),`utf-8`));async function h(){let e=new a;e.name(`kick`).description(`KickJS — A production-grade, decorator-driven Node.js framework`).version(m.version);let o=i(process.cwd()),s=o,c=await t(s)??{},l=n([...r,...c.plugins??[]],c.commands??[]);await l.register(e,{cwd:s,projectRoot:o,config:c,log:e=>console.log(e)}),d(e,{...c,commands:l.commands}),e.showHelpAfterError();let u=process.argv.map(e=>e===`-v`?`--version`:e);await e.parseAsync(u)}h().catch(e=>{console.error(e instanceof Error?e.message:e),process.exitCode=1});export{};
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs-cli v8.1.5
2
+ * @forinda/kickjs-cli v8.1.6
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,5 +8,5 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{t as e}from"./rolldown-runtime-DmTqmRjS.mjs";import{existsSync as t,mkdirSync as n,readFileSync as r,writeFileSync as i}from"node:fs";import{isAbsolute as a,join as o,relative as s,resolve as c}from"node:path";import{access as l,readFile as u}from"node:fs/promises";var d=e({BUILTIN_REPO_TYPES:()=>p,DEPRECATED_REPO_TYPES:()=>m,PACKAGE_MANAGERS:()=>f,defineConfig:()=>g,hasDependency:()=>_,hasSwagger:()=>v,loadKickConfig:()=>w,resolveModuleConfig:()=>S,resolveSchemaLib:()=>y,resolveTokenScope:()=>b,validateAssetMap:()=>E,warnIfDeprecatedRepo:()=>h,writeAssetConfigSnapshot:()=>T});const f=[`pnpm`,`npm`,`yarn`,`bun`],p=[`inmemory`],m=[`prisma`,`drizzle`];function h(e){return m.includes(e)?(console.warn(` Note: '${e}' is no longer a built-in repository preset — a repository shaped to it is that library's interface, not KickJS's.\n Scaffolding a generic custom-repository stub instead; wire it to ${e} yourself.`),!0):!1}function g(e){return e}function _(e,n,i=`runtime`){try{let a=o(e,`package.json`);if(!t(a))return!1;let s=JSON.parse(r(a,`utf-8`));return s.dependencies?.[n]?!0:i===`any`&&!!s.devDependencies?.[n]}catch{return!1}}function v(e){return _(e,`@forinda/kickjs-swagger`,`runtime`)}function y(e){return _(e,`valibot`,`runtime`)?`valibot`:_(e,`yup`,`runtime`)?`yup`:`zod`}function b(e,n){if(e?.tokenScope&&typeof e.tokenScope==`string`&&e.tokenScope.length>0){let t=x(e.tokenScope);if(t.length>0)return t}try{let e=o(n,`package.json`);if(t(e)){let t=JSON.parse(r(e,`utf-8`));if(typeof t.name==`string`&&t.name.length>0){let e=t.name.match(/^@([^/]+)\//),n=x(e?e[1]:t.name);if(n.length>0)return n}}}catch{}return`app`}function x(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,`-`).replace(/^-+|-+$/g,``).replace(/-{2,}/g,`-`)}function S(e){if(!e)return{};let t={dir:e.modules?.dir,repo:e.modules?.repo,schemaDir:e.modules?.schemaDir,pluralize:e.modules?.pluralize,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`&&!p.includes(t.repo)&&(h(t.repo)||console.warn(` Warning: modules.repo '${t.repo}' is not a built-in type (${p.join(`, `)}). It will generate a stub repository. Use { name: '${t.repo}' } to silence this warning.`)),t}const C=[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`,`kick.config.json`];async function w(e){let{findProjectRoot:t}=await import(`./project-root-BsyQhlS5.mjs`).then(e=>e.n),n=t(e);for(let e of C){let t=o(n,e);try{await l(t)}catch{continue}if(e.endsWith(`.json`)){let e=await u(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=E(e,n);for(let e of i)console.warn(` Warning: ${e}`);return T(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=E(i,n);for(let e of a)console.warn(` Warning: ${e}`);return T(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 T(e,t){if(!(!t?.assetMap||Object.keys(t.assetMap).length===0))try{let r=o(e,`.kickjs`);n(r,{recursive:!0});let a={version:1,assetMap:t.assetMap,...t.build?.outDir?{build:{outDir:t.build.outDir}}:{}};i(o(r,`kick.config.json`),JSON.stringify(a,null,2)+`
11
+ import{t as e}from"./rolldown-runtime-D-i_dFAb.mjs";import{existsSync as t,mkdirSync as n,readFileSync as r,writeFileSync as i}from"node:fs";import{isAbsolute as a,join as o,relative as s,resolve as c}from"node:path";import{access as l,readFile as u}from"node:fs/promises";var d=e({BUILTIN_REPO_TYPES:()=>p,DEPRECATED_REPO_TYPES:()=>m,PACKAGE_MANAGERS:()=>f,defineConfig:()=>g,hasDependency:()=>_,hasSwagger:()=>v,loadKickConfig:()=>w,resolveModuleConfig:()=>S,resolveSchemaLib:()=>y,resolveTokenScope:()=>b,validateAssetMap:()=>E,warnIfDeprecatedRepo:()=>h,writeAssetConfigSnapshot:()=>T});const f=[`pnpm`,`npm`,`yarn`,`bun`],p=[`inmemory`],m=[`prisma`,`drizzle`];function h(e){return m.includes(e)?(console.warn(` Note: '${e}' is no longer a built-in repository preset — a repository shaped to it is that library's interface, not KickJS's.\n Scaffolding a generic custom-repository stub instead; wire it to ${e} yourself.`),!0):!1}function g(e){return e}function _(e,n,i=`runtime`){try{let a=o(e,`package.json`);if(!t(a))return!1;let s=JSON.parse(r(a,`utf-8`));return s.dependencies?.[n]?!0:i===`any`&&!!s.devDependencies?.[n]}catch{return!1}}function v(e){return _(e,`@forinda/kickjs-swagger`,`runtime`)}function y(e){return _(e,`valibot`,`runtime`)?`valibot`:_(e,`yup`,`runtime`)?`yup`:`zod`}function b(e,n){if(e?.tokenScope&&typeof e.tokenScope==`string`&&e.tokenScope.length>0){let t=x(e.tokenScope);if(t.length>0)return t}try{let e=o(n,`package.json`);if(t(e)){let t=JSON.parse(r(e,`utf-8`));if(typeof t.name==`string`&&t.name.length>0){let e=t.name.match(/^@([^/]+)\//),n=x(e?e[1]:t.name);if(n.length>0)return n}}}catch{}return`app`}function x(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,`-`).replace(/^-+|-+$/g,``).replace(/-{2,}/g,`-`)}function S(e){if(!e)return{};let t={dir:e.modules?.dir,repo:e.modules?.repo,schemaDir:e.modules?.schemaDir,pluralize:e.modules?.pluralize,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`&&!p.includes(t.repo)&&(h(t.repo)||console.warn(` Warning: modules.repo '${t.repo}' is not a built-in type (${p.join(`, `)}). It will generate a stub repository. Use { name: '${t.repo}' } to silence this warning.`)),t}const C=[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`,`kick.config.json`];async function w(e){let{findProjectRoot:t}=await import(`./project-root-BhBKSGeK.mjs`).then(e=>e.n),n=t(e);for(let e of C){let t=o(n,e);try{await l(t)}catch{continue}if(e.endsWith(`.json`)){let e=await u(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=E(e,n);for(let e of i)console.warn(` Warning: ${e}`);return T(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=E(i,n);for(let e of a)console.warn(` Warning: ${e}`);return T(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 T(e,t){if(!(!t?.assetMap||Object.keys(t.assetMap).length===0))try{let r=o(e,`.kickjs`);n(r,{recursive:!0});let a={version:1,assetMap:t.assetMap,...t.build?.outDir?{build:{outDir:t.build.outDir}}:{}};i(o(r,`kick.config.json`),JSON.stringify(a,null,2)+`
12
12
  `,`utf-8`)}catch{}}function E(e,n){let r=[];if(!e?.assetMap)return r;let i=c(n);for(let[a,o]of Object.entries(e.assetMap)){if(!a||a.includes(`/`)){r.push(`assetMap key '${a}' is invalid — must be a non-empty string without '/'`);continue}if(typeof o?.src!=`string`||o.src.length===0){r.push(`assetMap.${a} is missing a non-empty 'src' field`);continue}t(c(n,o.src))||r.push(`assetMap.${a}.src ('${o.src}') does not exist — typegen + build will fail`),o.dest&&D(c(n,o.dest),i)&&r.push(`assetMap.${a}.dest ('${o.dest}') resolves outside the project root — refusing to copy`)}return r}function D(e,t){let n=s(t,e);return n===``?!1:n.startsWith(`..`)||a(n)}export{w as a,b as c,v as i,h as l,d as n,S as o,_ as r,y as s,f as t};