@teispace/next-maker 5.0.0 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,21 +1,21 @@
1
1
  #!/usr/bin/env node
2
- import{Command as mp}from"commander";var Te={name:"@teispace/next-maker",version:"5.0.0",description:"Create and grow Next.js 16 applications from the Teispace starter: composable init, feature-aware setup and doctor, and generators for the server-first data layer.",keywords:["nextjs","react","typescript","tailwindcss","starter","template","redux","zustand","tanstack-query","server-actions","cli"],type:"module",homepage:"https://github.com/teispace/npm-packages/tree/main/packages/next-maker#readme",bugs:{url:"https://github.com/teispace/npm-packages/issues"},license:"MIT",author:"Teispace",files:["dist","README.md","LICENSE","CHANGELOG.md"],bin:"dist/index.js",repository:{type:"git",url:"git+https://github.com/teispace/npm-packages.git",directory:"packages/next-maker"},scripts:{build:"tsx build.ts",start:"node dist/index.js",dev:"tsx --watch src/index.ts",test:"vitest run","test:watch":"vitest","test:cov":"vitest run --coverage","type-check":"tsc --noEmit",clean:"rm -rf dist",prepublishOnly:"yarn clean && yarn build",smoke:"tsx scripts/smoke.ts"},dependencies:{commander:"^15.0.0",degit:"^3.8.0",enquirer:"^2.4.1",ora:"^9.4.1",picocolors:"^1.1.1","png-to-ico":"^3.0.2",sharp:"^0.35.3"},devDependencies:{"@types/degit":"^2.8.6","@types/node":"^26.2.0",esbuild:"^0.28.2",tsx:"^4.23.12",typescript:"^6.0.3",vitest:"^4.1.11"},engines:{node:">=24.0.0"},publishConfig:{access:"public",registry:"https://registry.npmjs.org/"}};import{copyFile as Ui}from"node:fs/promises";import Ct from"node:path";import A from"picocolors";var Xr=/@next-maker:([\w-]+)(?::(start|end))?/,Fs=/^\s*(?:\{\s*\/\*.*?\*\/\s*\}|\/\*.*?\*\/|\/\/.*|#.*)\s*$/,Ms=e=>e.replace(/\s*\{\s*\/\*[^*]*@next-maker:[^*]*\*\/\s*\}\s*$/,"").replace(/\s*\/\*[^*]*@next-maker:[^*]*\*\/\s*$/,"").replace(/\s*\/\/[^\n]*@next-maker:[^\n]*$/,"").replace(/\s*#[^\n]*@next-maker:[^\n]*$/,""),zt=(e,{off:t})=>{let r=e.split(`
3
- `),n=[];for(let o=0;o<r.length;o++){let s=r[o],i=s.match(Xr);if(!i){n.push(s);continue}let[,a,p]=i,m=t.has(a);if(p==="start"){let d=_s(r,o+1,a);m&&(o=d);continue}if(p==="end")continue;let c=Fs.test(s);if(m){c&&o++;continue}c||n.push(Ms(s))}return n.join(`
4
- `)},_s=(e,t,r)=>{for(let n=t;n<e.length;n++){let o=e[n].match(Xr);if(o&&o[1]===r&&o[2]==="end")return n}throw new Error(`Anchor @next-maker:${r}:start has no matching :end`)},Je=e=>e.includes("@next-maker:"),Yr=(e,t)=>{let r=e.split(`
5
- `),n=[],o=new RegExp(`^import\\s+${t}\\s+from\\s+['"][^'"]+['"];?\\s*$`),s=/^(import\s+(?:type\s+)?)\{([^}]+)\}(\s+from\s+['"][^'"]+['"];?\s*)$/;for(let i of r){if(o.test(i))continue;let a=i.match(s);if(a){let p=a[2].split(",").map(c=>c.trim()).filter(Boolean),m=p.filter(c=>c.replace(/^type\s+/,"").split(/\s+as\s+/)[0]!==t);if(m.length===0)continue;if(m.length<p.length){n.push(`${a[1]}{ ${m.join(", ")} }${a[3]}`);continue}}n.push(i)}return n.join(`
6
- `)},ze=(e,t)=>{let r=e.split(`
7
- `),n=new RegExp(`^([ \\t]*)<${t}\\b`),o=-1,s="";for(let u=0;u<r.length;u++){let f=r[u].match(n);if(f){o=u,s=f[1];break}}if(o===-1)return e;let i=o;for(;i<r.length&&!/>\s*$/.test(r[i]);)i++;if(i>=r.length)throw new Error(`unwrapJsx: opening <${t}> never closes`);if(/\/>\s*$/.test(r[i]))return e;let a=s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),p=new RegExp(`^${a}</${t}>\\s*$`),m=-1;for(let u=i+1;u<r.length;u++)if(p.test(r[u])){m=u;break}if(m===-1)throw new Error(`unwrapJsx: no closing </${t}> at the opening indent`);let c=r.slice(i+1,m).map(u=>u.startsWith(" ")?u.slice(2):u),d=[...r.slice(0,o),...c,...r.slice(m+1)].join(`
8
- `);return Yr(d,t)},We=(e,t)=>{let r=new RegExp(`\\b${t}\\(`,"g"),n=e,o=r.exec(n);for(;o;){let s=o.index,i=0,a=s+o[0].length-1;for(;a<n.length;a++)if(n[a]==="(")i++;else if(n[a]===")"&&(i--,i===0))break;if(i!==0)throw new Error(`unwrapCall: unbalanced parentheses after ${t}(`);let p=n.slice(s+o[0].length,a);n=n.slice(0,s)+p+n.slice(a+1),r.lastIndex=s,o=r.exec(n)}return n};import{cp as on,mkdir as Js,mkdtemp as zs,readdir as rn,readFile as Oe,rm as Ht,rmdir as Ws,stat as Hs,writeFile as Ae}from"node:fs/promises";import{tmpdir as Ks}from"node:os";import N from"node:path";import{readdir as Ds}from"node:fs/promises";import gt from"node:path";var Qr=e=>{let t="^";for(let r=0;r<e.length;r++){let n=e[r];n==="*"?e[r+1]==="*"?(r++,e[r+1]==="/"?(r++,t+="(?:.*/)?"):t+=".*"):t+="[^/]*":t+=n.replace(/[.+?^${}()|[\]\\]/g,"\\$&")}return new RegExp(`${t}$`)},Ls=new Set(["node_modules",".git",".next","coverage","playwright-report","test-results"]),L=async(e,t=Ls)=>{let r=[],n=async o=>{let s;try{s=await Ds(o,{withFileTypes:!0})}catch{return}for(let i of s)if(i.isDirectory()){if(t.has(i.name))continue;await n(gt.join(o,i.name))}else i.isFile()&&r.push(gt.relative(e,gt.join(o,i.name)).split(gt.sep).join("/"))};return await n(e),r.sort()},se=(e,t)=>{let r=Qr(t);return e.filter(n=>r.test(n))};import{readFile as Us}from"node:fs/promises";import Gs from"node:path";var ht="next-maker.json",ge=".next-maker/overlays",Zr=1,G=e=>{throw new Error(`Invalid ${ht}: ${e}`)},tn=e=>{(typeof e!="object"||e===null)&&G("not an object");let t=e;t.manifestVersion!==Zr&&G(`manifestVersion ${String(t.manifestVersion)} is not supported by this CLI (expected ${Zr})`),(!t.starter?.name||!t.starter.version)&&G("starter.name and starter.version are required"),(!t.options||typeof t.options!="object")&&G("options is required"),(!t.features||typeof t.features!="object")&&G("features is required"),(!t.packageManagers||typeof t.packageManagers!="object")&&G("packageManagers is required");let r=t.options,n=t.features;for(let[o,s]of Object.entries(r))["choice","boolean","multi"].includes(s.type)||G(`option ${o} has unknown type ${String(s.type)}`),s.type!=="boolean"&&!Array.isArray(s.values)&&G(`option ${o} needs a values array`),s.default===void 0&&G(`option ${o} needs a default`);for(let[o,s]of Object.entries(n)){(!s.when||typeof s.when!="object")&&G(`feature ${o} needs a when`);for(let i of Object.keys(s.when))r[i]||G(`feature ${o} refers to unknown option ${i}`)}return{...t,always:{remove:t.always?.remove??[]}}},He=async e=>{let t=Gs.join(e,ht),r;try{r=await Us(t,"utf-8")}catch{throw new Error(`The starter at ${e} has no ${ht}. This CLI needs a starter that ships a composition manifest (nextjs-starter 2.x or later).`)}return tn(JSON.parse(r))},en=(e,t)=>e.some(r=>r===t),yt=(e,t,r)=>t===void 0?!1:e?.type==="multi"&&Array.isArray(t)?t.some(n=>en(r,n)):en(r,t),ie=(e,t,r)=>Object.entries(t.when).every(([n,o])=>yt(e.options[n],r[n],o)),Bs=e=>e.type==="boolean"?!1:e.type==="multi"?[]:e.default,Vs=(e,t,r)=>{if(e.type==="boolean"){if(typeof r=="boolean")return r;if(r==="true")return!0;if(r==="false")return!1;throw new Error(`Option ${t} expects true or false, got ${String(r)}`)}if(e.type==="multi"){let s=(Array.isArray(r)?r:String(r).split(",")).map(i=>String(i).trim()).filter(Boolean);for(let i of s)if(!e.values?.includes(i))throw new Error(`Option ${t} does not accept ${i}; valid: ${e.values?.join(", ")}`);return s}let n=String(r);if(!e.values?.includes(n))throw new Error(`Option ${t} does not accept ${n}; valid: ${e.values?.join(", ")}`);return n},Ke=(e,t={})=>{let r={},n=[],o=Object.keys(t).filter(s=>!e.options[s]);for(let[s,i]of Object.entries(e.options)){let a=t[s];r[s]=a===void 0?i.default:Vs(i,s,a)}for(let[s,i]of Object.entries(e.options))if(i.requires)for(let[a,p]of Object.entries(i.requires)){if(yt(e.options[a],r[a],p))continue;let m=Bs(i);r[s]!==m&&JSON.stringify(r[s])!==JSON.stringify(m)&&(n.push({option:s,value:m,reason:`${s} requires ${a} to be ${p.map(String).join(" or ")}`}),r[s]=m)}return{answers:r,forced:n,unknown:o}};var ae=(e,t)=>{switch(e){case"npm":return`npm run ${t}`;case"bun":return`bun run ${t}`;case"yarn":return`yarn ${t}`;default:return`pnpm ${t}`}},qs=e=>{switch(e){case"npm":return[[/\bpnpm install --frozen-lockfile\b/g,"npm ci"],[/\bpnpm install\b/g,"npm install"],[/\bpnpm add -D\b/g,"npm install --save-dev"],[/\bpnpm add\b/g,"npm install"],[/\bpnpm dlx\b/g,"npx"],[/\bpnpm exec\b/g,"npx --no --"],[/\bpnpm ([\w:.-]+)/g,"npm run $1"]];case"yarn":return[[/\bpnpm install --frozen-lockfile\b/g,"yarn install --immutable"],[/\bpnpm install\b/g,"yarn install"],[/\bpnpm add -D\b/g,"yarn add -D"],[/\bpnpm add\b/g,"yarn add"],[/\bpnpm dlx\b/g,"yarn dlx"],[/\bpnpm exec\b/g,"yarn"],[/\bpnpm ([\w:.-]+)/g,"yarn $1"]];case"bun":return[[/\bpnpm install --frozen-lockfile\b/g,"bun install --frozen-lockfile"],[/\bpnpm install\b/g,"bun install"],[/\bpnpm add -D\b/g,"bun add -d"],[/\bpnpm add\b/g,"bun add"],[/\bpnpm dlx\b/g,"bunx"],[/\bpnpm exec\b/g,"bunx"],[/\bpnpm ([\w:.-]+)/g,"bun run $1"]];default:return[]}},wt=(e,t)=>{if(t==="pnpm")return e;let r=e;for(let[n,o]of qs(t))r=r.replace(n,o);return r},Wt=e=>e==="package.json"||e.startsWith(".husky/")||e.endsWith(".md")||e===".lintstagedrc.mjs";var he=e=>[...new Set(e)],Xt=(e,t,r)=>{let n=e.packageManagers[r];if(!n)throw new Error(`This starter does not support ${r}; valid: ${Object.keys(e.packageManagers).join(", ")}`);let o=[],s=[],i=[],a=[],p=[];for(let[c,d]of Object.entries(e.features)){let u=ie(e,d,t);(u?o:s).push(c);let f=u?d.on:d.off;if(!f)continue;i.push(f);let h=Object.keys(d.when);f.overlay&&!a.some(w=>w.name===f.overlay)&&a.push({name:f.overlay,options:h}),f.remove?.length&&p.push({feature:c,options:h,patterns:f.remove})}let m=he([...e.always.remove,...n.remove??[]]);return{answers:t,packageManager:r,pmSpec:n,featuresOn:o,featuresOff:s,pmOverlays:n.overlay?[n.overlay]:[],featureOverlays:a,removePatterns:he([...m,...p.flatMap(c=>c.patterns)]),unconditionalRemovals:m,featureRemovals:p,anchorsOff:new Set(i.flatMap(c=>c.anchors??[])),unwrapJsx:i.flatMap(c=>c.unwrapJsx??[]),unwrapCall:i.flatMap(c=>c.unwrapCall??[]),packages:he(i.flatMap(c=>c.packages??[])),devPackages:he(i.flatMap(c=>c.devPackages??[])),scripts:he(i.flatMap(c=>c.scripts??[])),env:he(i.flatMap(c=>c.env??[])),packageJsonKeys:he(i.flatMap(c=>c.packageJsonKeys??[]))}},Xs=new Set([".ts",".tsx",".js",".mjs",".cjs",".css",".json",".yml",".yaml",".md",".sh",".example",".mdx"]),Ys=e=>Xs.has(N.extname(e))||e.startsWith(".husky/")||e==="Dockerfile",nn=async(e,t,r)=>{let n=N.join(e,r),o=await L(n,new Set);if(o.length===0)throw new Error(`Overlay "${r}" is missing or empty at ${ge}/${r}`);for(let s of o){let i=N.join(t,s);await Js(N.dirname(i),{recursive:!0}),await on(N.join(n,s),i,{force:!0})}return o},Yt=async(e,t=e)=>{let r;try{r=await rn(t,{withFileTypes:!0})}catch{return}for(let n of r)n.isDirectory()&&n.name!=="node_modules"&&n.name!==".git"&&await Yt(e,N.join(t,n.name));t!==e&&(await rn(t)).length===0&&await Ws(t)},sn=(e,t)=>{let r=t.split("."),n=e;for(let s of r.slice(0,-1)){let i=n?.[s];if(typeof i!="object"||i===null)return;n=i}let o=r[r.length-1];if(n&&o in n&&delete n[o],r.length>1){let s=r.slice(0,-1).join("."),i=r.slice(0,-1).reduce((a,p)=>a?.[p],e);i&&typeof i=="object"&&Object.keys(i).length===0&&sn(e,s)}},Qs=async(e,t,r)=>{let n=N.join(e,"package.json"),o=JSON.parse(await Oe(n,"utf-8"));for(let i of t.packages)delete o.dependencies?.[i];for(let i of t.devPackages)delete o.devDependencies?.[i];for(let i of t.scripts)delete o.scripts?.[i];for(let i of t.packageJsonKeys)sn(o,i);let s=r.validateScript;if(s&&o.scripts?.[s.name]){let i=s.steps.filter(a=>o.scripts[a]);o.scripts[s.name]=i.map(a=>ae(t.packageManager,a)).join(" && ")}if(o.scripts)for(let[i,a]of Object.entries(o.scripts))typeof a=="string"&&(o.scripts[i]=wt(a,t.packageManager));if(t.pmSpec.packageManager?o.packageManager=t.pmSpec.packageManager:delete o.packageManager,o.engines){for(let i of Object.keys(r.packageManagers))delete o.engines[i];Object.assign(o.engines,t.pmSpec.engines??{})}await Ae(n,`${JSON.stringify(o,null,2)}
9
- `,"utf-8")},Zs=async(e,t)=>{let r=N.join(e,".env.example"),n;try{n=await Oe(r,"utf-8")}catch{return}for(let o of t)n=n.replace(new RegExp(`^${o}=.*\\n?`,"gm"),"");await Ae(r,n.replace(/\n{3,}/g,`
10
-
11
- `),"utf-8")},Qt=async(e,t,r)=>{let n={removed:[],overlaid:[],anchored:[],unwrapped:[]},o=N.join(e,ge),s=await zs(N.join(Ks(),"next-maker-overlays-"));try{await Kt(o)&&await on(o,s,{recursive:!0});for(let m of r.pmOverlays)n.overlaid.push(...await nn(s,e,m));let a=await L(e),p=new Set(r.removePatterns.flatMap(m=>se(a,m)));for(let m of p)await Ht(N.join(e,m),{force:!0}),n.removed.push(m);for(let m of r.featureOverlays){let c=await nn(s,e,m.name),d=[...r.unconditionalRemovals,...r.featureRemovals.filter(f=>!f.options.some(h=>m.options.includes(h))).flatMap(f=>f.patterns)],u=new Set(d.flatMap(f=>se(c,f)));for(let f of u)await Ht(N.join(e,f),{force:!0}),n.removed.push(f);n.overlaid.push(...c.filter(f=>!u.has(f)))}}finally{await Ht(s,{recursive:!0,force:!0})}await Yt(e);let i=await L(e);for(let a of i){if(!Ys(a))continue;let p=N.join(e,a),m=await Oe(p,"utf-8");Je(m)&&(await Ae(p,zt(m,{off:r.anchorsOff}),"utf-8"),n.anchored.push(a))}for(let{file:a,tag:p}of r.unwrapJsx){let m=N.join(e,a);if(!await Kt(m))continue;let c=await Oe(m,"utf-8"),d=ze(c,p);d!==c&&(await Ae(m,d,"utf-8"),n.unwrapped.push(`${a}:<${p}>`))}for(let{file:a,name:p}of r.unwrapCall){let m=N.join(e,a);if(!await Kt(m))continue;let c=await Oe(m,"utf-8"),d=We(c,p);d!==c&&(await Ae(m,d,"utf-8"),n.unwrapped.push(`${a}:${p}()`))}if(await Qs(e,r,t),await Zs(e,r.env),r.packageManager!=="pnpm")for(let a of await L(e)){if(!Wt(a)||a==="package.json")continue;let p=N.join(e,a),m=await Oe(p,"utf-8"),c=wt(m,r.packageManager);c!==m&&await Ae(p,c,"utf-8")}return n},Kt=async e=>{try{return await Hs(e),!0}catch{return!1}};import{readFile as ei}from"node:fs/promises";import ti from"node:path";var Zt=async e=>{let t=ti.resolve(process.cwd(),e),r;try{r=await ei(t,"utf-8")}catch{throw new Error(`Config file not found: ${t}`)}let n=JSON.parse(r);if(typeof n!="object"||n===null||Array.isArray(n))throw new Error(`Config file ${t} must contain a JSON object`);if(n.options!==void 0&&(typeof n.options!="object"||n.options===null))throw new Error(`Config file ${t}: "options" must be an object`);return n},ye=e=>{let t={};for(let r of e??[]){let n=r.indexOf("=");if(n<=0)throw new Error(`--set expects key=value, got "${r}"`);t[r.slice(0,n).trim()]=r.slice(n+1).trim()}return t};var er={default:{description:"Manifest defaults: Redux, fetch, i18n, dark mode, unit + e2e tests, hooks",answers:{}},minimal:{description:"No state store, no i18n, no dark mode, no tests, no hooks",answers:{state:"none",i18n:!1,darkMode:!1,tests:!1,e2e:!1,hooks:!1,commitizen:!1}},full:{description:"Everything on: WebSocket, both HTTP adapters, Docker, CI, analyzer, OpenAPI, templates",answers:{ws:!0,http:"both",docker:!0,ci:!0,analyzer:!0,openapi:!0,githubTemplates:!0,communityFiles:["CODE_OF_CONDUCT.md","CONTRIBUTING.md","SECURITY.md"]}},zustand:{description:"Defaults with Zustand instead of Redux",answers:{state:"zustand"}},spa:{description:"Client-heavy app: Zustand, Axios, no i18n, Docker and CI on",answers:{state:"zustand",http:"axios",i18n:!1,docker:!0,ci:!0}}},Ie=()=>Object.keys(er),Ne=e=>{let t=er[e];if(!t)throw new Error(`Unknown preset "${e}". Valid: ${Ie().join(", ")}.`);return{...t.answers}};var Xe=new Set;function xt(e){return Xe.add(e),()=>Xe.delete(e)}function an(e){let{logger:t=p=>console.error(p),exitOnCancel:r=process.env.NODE_ENV!=="test"}=e??{},n=!1,o=async()=>{let p=[...Xe];Xe.clear();for(let m of p)try{await m()}catch(c){t(`Cleanup failed: ${c instanceof Error?c.message:String(c)}`)}},s=()=>{if(n){r&&process.exit(130);return}n=!0;let p=Xe.size>0;o().then(()=>{console.log(""),t("Setup cancelled by user"),console.log(""),r&&process.exit(p?130:0)})},i=p=>{if(p!==null&&typeof p=="object"&&"code"in p&&p.code==="ERR_USE_AFTER_CLOSE"){s();return}if(p instanceof Error){t(`Uncaught exception: ${p.message}`);return}t(`Uncaught exception: ${String(p)}`)},a=p=>{if(p instanceof Error){t(`Unhandled promise rejection: ${p.message}`);return}t(`Unhandled promise rejection: ${String(p)}`)};return process.on("SIGINT",s),process.on("SIGTERM",s),process.on("uncaughtException",i),process.on("unhandledRejection",a),()=>{process.off("SIGINT",s),process.off("SIGTERM",s),process.off("uncaughtException",i),process.off("unhandledRejection",a)}}import z from"picocolors";var ri={reset:e=>e,red:z.red,green:z.green,yellow:z.yellow,blue:z.blue,cyan:z.cyan,magenta:z.magenta,white:z.white,gray:z.gray,bright:z.bold,dim:z.dim};function ce(e,t="reset"){let r=ri[t]??(n=>n);console.log(r(e))}function bt(e){ce(`\u2716 ${e}`,"red")}var x=bt;function cn(e){ce(`\u26A0 ${e}`,"yellow")}function l(e){ce(e)}function vt(){console.log(""),ce("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557","cyan"),ce("\u2551 \u2551","cyan"),ce("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),ce("\u2551 \u2551","cyan"),ce("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D","cyan"),console.log("")}import ni from"ora";function $t(e="",t){let r=ni({text:e,...t});return r.start(),r}var oi=e=>e.charAt(0).toUpperCase()+e.slice(1),U=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),$=e=>oi(U(e));import si from"ora";var g=si();import{execFile as ii}from"node:child_process";import{cp as pn,mkdir as ai,stat as ci}from"node:fs/promises";import Ye from"node:path";import{promisify as pi}from"node:util";import li from"degit";var mi=pi(ii),ln="teispace/nextjs-starter",Pt="v2.0.0-alpha.0",di="NEXT_MAKER_STARTER_PATH",ui=(e=Pt)=>e==="main"?ln:`${ln}#${e}`,B=(e={})=>{let t=e.starterPath??process.env[di];return t?{kind:"local",location:Ye.resolve(t)}:{kind:"remote",location:ui(e.ref)}},fi=new Set(["node_modules",".git",".next","coverage","playwright-report","test-results",".env"]),kt=async(e,t={})=>{let r=t.source??B();if(r.kind==="local"){try{if(!(await ci(r.location)).isDirectory())throw new Error("not a directory")}catch{throw new Error(`Starter path ${r.location} is not a directory`)}return await gi(r.location,e),r}return await li(r.location,{cache:!1,force:!0,verbose:t.verbose??!1}).clone(e),r},gi=async(e,t)=>{let r=null;try{let{stdout:n}=await mi("git",["-C",e,"ls-files","-z","--cached","--others","--exclude-standard"],{maxBuffer:67108864});r=n.split("\0").filter(Boolean)}catch{r=null}if(r===null){await pn(e,t,{recursive:!0,filter:n=>!fi.has(Ye.basename(n))});return}for(let n of r){let o=Ye.join(t,n);await ai(Ye.dirname(o),{recursive:!0});try{await pn(Ye.join(e,n),o)}catch{}}};import{existsSync as tr}from"node:fs";import Qe from"node:fs/promises";import hi from"node:path";var j=async e=>Qe.readFile(e,"utf-8"),k=async(e,t)=>{await Qe.mkdir(hi.dirname(e),{recursive:!0}),await Qe.writeFile(e,t,"utf-8")};var mn=async e=>{tr(e)&&await Qe.unlink(e)},Ze=async e=>{tr(e)&&await Qe.rm(e,{recursive:!0,force:!0})},dn=async(e,t)=>{let r=await j(e),n=JSON.parse(r),o=t(n);await k(e,JSON.stringify(o,null,2))},y=e=>tr(e);import{execFile as yi}from"node:child_process";import{promisify as wi}from"node:util";var xi=wi(yi),Z=(e,t)=>xi("git",e,t?{cwd:t}:void 0);function bi(e){let t=e.trim();if(!t||t.startsWith("-"))throw new Error(`Invalid git remote "${e}".`);if(!(/^https?:\/\/\S+$/.test(t)||/^git@[\w.-]+:\S+$/.test(t)||/^ssh:\/\/\S+$/.test(t)||/^[\w.-]+\/[\w.-]+$/.test(t)))throw new Error(`Invalid git remote "${e}". Expected an https/ssh URL or "owner/repo".`)}var St=async(e,t,r)=>{try{if(await Z(["init"],e),await Z(["add","."],e),await Z(["commit","-m","Initial commit from @teispace/next-maker"],e),t&&(bi(t),await Z(["remote","add","origin",t],e),r)){await Z(["fetch","origin"],e);let n="main";try{await Z(["show-branch","origin/main"],e)}catch{try{await Z(["show-branch","origin/master"],e),n="master"}catch{n="main"}}await Z(["merge",`origin/${n}`,"--allow-unrelated-histories","-X","ours"],e),await Z(["push","origin",`HEAD:${n}`],e)}}catch(n){console.warn("Failed to initialize git repository",n)}};import{execFile as vi}from"node:child_process";import{promisify as $i}from"node:util";var Pi=$i(vi),un=(e,t,r)=>Pi(e,t,{cwd:r,maxBuffer:64*1024*1024}),ki=e=>{let t=e;return(`${t.stdout??""}
2
+ import{Command as Ip}from"commander";var Ae={name:"@teispace/next-maker",version:"5.0.1",description:"Create and grow Next.js 16 applications from the Teispace starter: composable init, feature-aware setup and doctor, and generators for the server-first data layer.",keywords:["nextjs","react","typescript","tailwindcss","starter","template","redux","zustand","tanstack-query","server-actions","cli"],type:"module",homepage:"https://github.com/teispace/npm-packages/tree/main/packages/next-maker#readme",bugs:{url:"https://github.com/teispace/npm-packages/issues"},license:"MIT",author:"Teispace",files:["dist","README.md","LICENSE","CHANGELOG.md"],bin:"dist/index.js",repository:{type:"git",url:"git+https://github.com/teispace/npm-packages.git",directory:"packages/next-maker"},scripts:{build:"tsx build.ts",start:"node dist/index.js",dev:"tsx --watch src/index.ts",test:"vitest run","test:watch":"vitest","test:cov":"vitest run --coverage","type-check":"tsc --noEmit",clean:"rm -rf dist",prepublishOnly:"yarn clean && yarn build",smoke:"tsx scripts/smoke.ts"},dependencies:{commander:"^15.0.0",degit:"^3.8.0",enquirer:"^2.4.1",ora:"^9.4.1",picocolors:"^1.1.1","png-to-ico":"^3.0.2",sharp:"^0.35.3"},devDependencies:{"@types/degit":"^2.8.6","@types/node":"^26.2.0",esbuild:"^0.28.2",tsx:"^4.23.12",typescript:"^6.0.3",vitest:"^4.1.11"},engines:{node:">=24.0.0"},publishConfig:{access:"public",registry:"https://registry.npmjs.org/"}};import{copyFile as Qi}from"node:fs/promises";import At from"node:path";import I from"picocolors";var on=/@next-maker:([\w-]+)(?::(start|end))?/,zs=/^\s*(?:\{\s*\/\*.*?\*\/\s*\}|\/\*.*?\*\/|\/\/.*|#.*)\s*$/,Ws=e=>e.replace(/\s*\{\s*\/\*[^*]*@next-maker:[^*]*\*\/\s*\}\s*$/,"").replace(/\s*\/\*[^*]*@next-maker:[^*]*\*\/\s*$/,"").replace(/\s*\/\/[^\n]*@next-maker:[^\n]*$/,"").replace(/\s*#[^\n]*@next-maker:[^\n]*$/,""),Xt=(e,{off:t})=>{let r=e.split(`
3
+ `),n=[];for(let o=0;o<r.length;o++){let s=r[o],i=s.match(on);if(!i){n.push(s);continue}let[,a,c]=i,l=t.has(a);if(c==="start"){let u=Ks(r,o+1,a);l&&(o=u);continue}if(c==="end")continue;let p=zs.test(s);if(l){p&&o++;continue}p||n.push(Ws(s))}return n.join(`
4
+ `)},Ks=(e,t,r)=>{for(let n=t;n<e.length;n++){let o=e[n].match(on);if(o&&o[1]===r&&o[2]==="end")return n}throw new Error(`Anchor @next-maker:${r}:start has no matching :end`)},ze=e=>e.includes("@next-maker:"),sn=(e,t)=>{let r=e.split(`
5
+ `),n=[],o=new RegExp(`^import\\s+${t}\\s+from\\s+['"][^'"]+['"];?\\s*$`),s=/^(import\s+(?:type\s+)?)\{([^}]+)\}(\s+from\s+['"][^'"]+['"];?\s*)$/;for(let i of r){if(o.test(i))continue;let a=i.match(s);if(a){let c=a[2].split(",").map(p=>p.trim()).filter(Boolean),l=c.filter(p=>p.replace(/^type\s+/,"").split(/\s+as\s+/)[0]!==t);if(l.length===0)continue;if(l.length<c.length){n.push(`${a[1]}{ ${l.join(", ")} }${a[3]}`);continue}}n.push(i)}return n.join(`
6
+ `)},We=(e,t)=>{let r=e.split(`
7
+ `),n=new RegExp(`^([ \\t]*)<${t}\\b`),o=-1,s="";for(let f=0;f<r.length;f++){let d=r[f].match(n);if(d){o=f,s=d[1];break}}if(o===-1)return e;let i=o;for(;i<r.length&&!/>\s*$/.test(r[i]);)i++;if(i>=r.length)throw new Error(`unwrapJsx: opening <${t}> never closes`);if(/\/>\s*$/.test(r[i]))return e;let a=s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),c=new RegExp(`^${a}</${t}>\\s*$`),l=-1;for(let f=i+1;f<r.length;f++)if(c.test(r[f])){l=f;break}if(l===-1)throw new Error(`unwrapJsx: no closing </${t}> at the opening indent`);let p=r.slice(i+1,l).map(f=>f.startsWith(" ")?f.slice(2):f),u=[...r.slice(0,o),...p,...r.slice(l+1)].join(`
8
+ `);return sn(u,t)},Ke=(e,t)=>{let r=new RegExp(`\\b${t}\\(`,"g"),n=e,o=r.exec(n);for(;o;){let s=o.index,i=0,a=s+o[0].length-1;for(;a<n.length;a++)if(n[a]==="(")i++;else if(n[a]===")"&&(i--,i===0))break;if(i!==0)throw new Error(`unwrapCall: unbalanced parentheses after ${t}(`);let c=n.slice(s+o[0].length,a);n=n.slice(0,s)+c+n.slice(a+1),r.lastIndex=s,o=r.exec(n)}return n};import{cp as dn,mkdir as ni,mkdtemp as oi,readdir as mn,readFile as Ie,rm as Qt,rmdir as si,stat as ii,writeFile as Ne}from"node:fs/promises";import{tmpdir as ai}from"node:os";import F from"node:path";import{readdir as Xs}from"node:fs/promises";import wt from"node:path";var an=e=>{let t="^";for(let r=0;r<e.length;r++){let n=e[r];n==="*"?e[r+1]==="*"?(r++,e[r+1]==="/"?(r++,t+="(?:.*/)?"):t+=".*"):t+="[^/]*":t+=n.replace(/[.+?^${}()|[\]\\]/g,"\\$&")}return new RegExp(`${t}$`)},Ys=new Set(["node_modules",".git",".next","coverage","playwright-report","test-results"]),L=async(e,t=Ys)=>{let r=[],n=async o=>{let s;try{s=await Xs(o,{withFileTypes:!0})}catch{return}for(let i of s)if(i.isDirectory()){if(t.has(i.name))continue;await n(wt.join(o,i.name))}else i.isFile()&&r.push(wt.relative(e,wt.join(o,i.name)).split(wt.sep).join("/"))};return await n(e),r.sort()},ie=(e,t)=>{let r=an(t);return e.filter(n=>r.test(n))};import{readFile as Qs}from"node:fs/promises";import Zs from"node:path";var xt="next-maker.json",ye=".next-maker/overlays",cn=1,B=e=>{throw new Error(`Invalid ${xt}: ${e}`)},ln=e=>{(typeof e!="object"||e===null)&&B("not an object");let t=e;t.manifestVersion!==cn&&B(`manifestVersion ${String(t.manifestVersion)} is not supported by this CLI (expected ${cn})`),(!t.starter?.name||!t.starter.version)&&B("starter.name and starter.version are required"),(!t.options||typeof t.options!="object")&&B("options is required"),(!t.features||typeof t.features!="object")&&B("features is required"),(!t.packageManagers||typeof t.packageManagers!="object")&&B("packageManagers is required");let r=t.options,n=t.features;for(let[o,s]of Object.entries(r))["choice","boolean","multi"].includes(s.type)||B(`option ${o} has unknown type ${String(s.type)}`),s.type!=="boolean"&&!Array.isArray(s.values)&&B(`option ${o} needs a values array`),s.default===void 0&&B(`option ${o} needs a default`);for(let[o,s]of Object.entries(n)){(!s.when||typeof s.when!="object")&&B(`feature ${o} needs a when`);for(let i of Object.keys(s.when))r[i]||B(`feature ${o} refers to unknown option ${i}`)}return{...t,always:{remove:t.always?.remove??[]}}},Xe=async e=>{let t=Zs.join(e,xt),r;try{r=await Qs(t,"utf-8")}catch{throw new Error(`The starter at ${e} has no ${xt}. This CLI needs a starter that ships a composition manifest (nextjs-starter 2.x or later).`)}return ln(JSON.parse(r))},pn=(e,t)=>e.some(r=>r===t),bt=(e,t,r)=>t===void 0?!1:e?.type==="multi"&&Array.isArray(t)?t.some(n=>pn(r,n)):pn(r,t),ae=(e,t,r)=>Object.entries(t.when).every(([n,o])=>bt(e.options[n],r[n],o)),ei=e=>e.type==="boolean"?!1:e.type==="multi"?[]:e.default,ti=(e,t,r)=>{if(e.type==="boolean"){if(typeof r=="boolean")return r;if(r==="true")return!0;if(r==="false")return!1;throw new Error(`Option ${t} expects true or false, got ${String(r)}`)}if(e.type==="multi"){let s=(Array.isArray(r)?r:String(r).split(",")).map(i=>String(i).trim()).filter(Boolean);for(let i of s)if(!e.values?.includes(i))throw new Error(`Option ${t} does not accept ${i}; valid: ${e.values?.join(", ")}`);return s}let n=String(r);if(!e.values?.includes(n))throw new Error(`Option ${t} does not accept ${n}; valid: ${e.values?.join(", ")}`);return n},Ye=(e,t={})=>{let r={},n=[],o=Object.keys(t).filter(s=>!e.options[s]);for(let[s,i]of Object.entries(e.options)){let a=t[s];r[s]=a===void 0?i.default:ti(i,s,a)}for(let[s,i]of Object.entries(e.options))if(i.requires)for(let[a,c]of Object.entries(i.requires)){if(bt(e.options[a],r[a],c))continue;let l=ei(i);r[s]!==l&&JSON.stringify(r[s])!==JSON.stringify(l)&&(n.push({option:s,value:l,reason:`${s} requires ${a} to be ${c.map(String).join(" or ")}`}),r[s]=l)}return{answers:r,forced:n,unknown:o}};var ce=(e,t)=>{switch(e){case"npm":return`npm run ${t}`;case"bun":return`bun run ${t}`;case"yarn":return`yarn ${t}`;default:return`pnpm ${t}`}},ri=e=>{switch(e){case"npm":return[[/\bpnpm install --frozen-lockfile\b/g,"npm ci"],[/\bpnpm install\b/g,"npm install"],[/\bpnpm add -D\b/g,"npm install --save-dev"],[/\bpnpm add\b/g,"npm install"],[/\bpnpm dlx\b/g,"npx"],[/\bpnpm exec\b/g,"npx --no --"],[/\bpnpm ([\w:.-]+)/g,"npm run $1"]];case"yarn":return[[/\bpnpm install --frozen-lockfile\b/g,"yarn install --immutable"],[/\bpnpm install\b/g,"yarn install"],[/\bpnpm add -D\b/g,"yarn add -D"],[/\bpnpm add\b/g,"yarn add"],[/\bpnpm dlx\b/g,"yarn dlx"],[/\bpnpm exec\b/g,"yarn"],[/\bpnpm ([\w:.-]+)/g,"yarn $1"]];case"bun":return[[/\bpnpm install --frozen-lockfile\b/g,"bun install --frozen-lockfile"],[/\bpnpm install\b/g,"bun install"],[/\bpnpm add -D\b/g,"bun add -d"],[/\bpnpm add\b/g,"bun add"],[/\bpnpm dlx\b/g,"bunx"],[/\bpnpm exec\b/g,"bunx"],[/\bpnpm ([\w:.-]+)/g,"bun run $1"]];default:return[]}},vt=(e,t)=>{if(t==="pnpm")return e;let r=e;for(let[n,o]of ri(t))r=r.replace(n,o);return r},Yt=e=>e==="package.json"||e.startsWith(".husky/")||e.endsWith(".md")||e===".lintstagedrc.mjs";var we=e=>[...new Set(e)],er=(e,t,r)=>{let n=e.packageManagers[r];if(!n)throw new Error(`This starter does not support ${r}; valid: ${Object.keys(e.packageManagers).join(", ")}`);let o=[],s=[],i=[],a=[],c=[];for(let[p,u]of Object.entries(e.features)){let f=ae(e,u,t);(f?o:s).push(p);let d=f?u.on:u.off;if(!d)continue;i.push(d);let g=Object.keys(u.when);d.overlay&&!a.some(y=>y.name===d.overlay)&&a.push({name:d.overlay,options:g}),d.remove?.length&&c.push({feature:p,options:g,patterns:d.remove})}let l=we([...e.always.remove,...n.remove??[]]);return{answers:t,packageManager:r,pmSpec:n,featuresOn:o,featuresOff:s,pmOverlays:n.overlay?[n.overlay]:[],featureOverlays:a,removePatterns:we([...l,...c.flatMap(p=>p.patterns)]),unconditionalRemovals:l,featureRemovals:c,anchorsOff:new Set(i.flatMap(p=>p.anchors??[])),unwrapJsx:i.flatMap(p=>p.unwrapJsx??[]),unwrapCall:i.flatMap(p=>p.unwrapCall??[]),packages:we(i.flatMap(p=>p.packages??[])),devPackages:we(i.flatMap(p=>p.devPackages??[])),scripts:we(i.flatMap(p=>p.scripts??[])),env:we(i.flatMap(p=>p.env??[])),packageJsonKeys:we(i.flatMap(p=>p.packageJsonKeys??[]))}},ci=new Set([".ts",".tsx",".js",".mjs",".cjs",".css",".json",".yml",".yaml",".md",".sh",".example",".mdx"]),pi=e=>ci.has(F.extname(e))||e.startsWith(".husky/")||e==="Dockerfile",un=async(e,t,r)=>{let n=F.join(e,r),o=await L(n,new Set);if(o.length===0)throw new Error(`Overlay "${r}" is missing or empty at ${ye}/${r}`);for(let s of o){let i=F.join(t,s);await ni(F.dirname(i),{recursive:!0}),await dn(F.join(n,s),i,{force:!0})}return o},tr=async(e,t=e)=>{let r;try{r=await mn(t,{withFileTypes:!0})}catch{return}for(let n of r)n.isDirectory()&&n.name!=="node_modules"&&n.name!==".git"&&await tr(e,F.join(t,n.name));t!==e&&(await mn(t)).length===0&&await si(t)},fn=(e,t)=>{let r=t.split("."),n=e;for(let s of r.slice(0,-1)){let i=n?.[s];if(typeof i!="object"||i===null)return;n=i}let o=r[r.length-1];if(n&&o in n&&delete n[o],r.length>1){let s=r.slice(0,-1).join("."),i=r.slice(0,-1).reduce((a,c)=>a?.[c],e);i&&typeof i=="object"&&Object.keys(i).length===0&&fn(e,s)}},li=async(e,t,r)=>{let n=F.join(e,"package.json"),o=JSON.parse(await Ie(n,"utf-8"));for(let i of t.packages)delete o.dependencies?.[i];for(let i of t.devPackages)delete o.devDependencies?.[i];for(let i of t.scripts)delete o.scripts?.[i];for(let i of t.packageJsonKeys)fn(o,i);let s=r.validateScript;if(s&&o.scripts?.[s.name]){let i=s.steps.filter(a=>o.scripts[a]);o.scripts[s.name]=i.map(a=>ce(t.packageManager,a)).join(" && ")}if(o.scripts)for(let[i,a]of Object.entries(o.scripts))typeof a=="string"&&(o.scripts[i]=vt(a,t.packageManager));if(t.pmSpec.packageManager?o.packageManager=t.pmSpec.packageManager:delete o.packageManager,o.engines){for(let i of Object.keys(r.packageManagers))delete o.engines[i];Object.assign(o.engines,t.pmSpec.engines??{})}await Ne(n,`${JSON.stringify(o,null,2)}
9
+ `,"utf-8")},mi=async(e,t)=>{let r=F.join(e,".env.example"),n;try{n=await Ie(r,"utf-8")}catch{return}for(let o of t)n=n.replace(new RegExp(`^${o}=.*\\n?`,"gm"),"");await Ne(r,n.replace(/\n{3,}/g,`
10
+
11
+ `),"utf-8")},rr=async(e,t,r)=>{let n={removed:[],overlaid:[],anchored:[],unwrapped:[]},o=F.join(e,ye),s=await oi(F.join(ai(),"next-maker-overlays-"));try{await Zt(o)&&await dn(o,s,{recursive:!0});for(let l of r.pmOverlays)n.overlaid.push(...await un(s,e,l));let a=await L(e),c=new Set(r.removePatterns.flatMap(l=>ie(a,l)));for(let l of c)await Qt(F.join(e,l),{force:!0}),n.removed.push(l);for(let l of r.featureOverlays){let p=await un(s,e,l.name),u=[...r.unconditionalRemovals,...r.featureRemovals.filter(d=>!d.options.some(g=>l.options.includes(g))).flatMap(d=>d.patterns)],f=new Set(u.flatMap(d=>ie(p,d)));for(let d of f)await Qt(F.join(e,d),{force:!0}),n.removed.push(d);n.overlaid.push(...p.filter(d=>!f.has(d)))}}finally{await Qt(s,{recursive:!0,force:!0})}await tr(e);let i=await L(e);for(let a of i){if(!pi(a))continue;let c=F.join(e,a),l=await Ie(c,"utf-8");ze(l)&&(await Ne(c,Xt(l,{off:r.anchorsOff}),"utf-8"),n.anchored.push(a))}for(let{file:a,tag:c}of r.unwrapJsx){let l=F.join(e,a);if(!await Zt(l))continue;let p=await Ie(l,"utf-8"),u=We(p,c);u!==p&&(await Ne(l,u,"utf-8"),n.unwrapped.push(`${a}:<${c}>`))}for(let{file:a,name:c}of r.unwrapCall){let l=F.join(e,a);if(!await Zt(l))continue;let p=await Ie(l,"utf-8"),u=Ke(p,c);u!==p&&(await Ne(l,u,"utf-8"),n.unwrapped.push(`${a}:${c}()`))}if(await li(e,r,t),await mi(e,r.env),r.packageManager!=="pnpm")for(let a of await L(e)){if(!Yt(a)||a==="package.json")continue;let c=F.join(e,a),l=await Ie(c,"utf-8"),p=vt(l,r.packageManager);p!==l&&await Ne(c,p,"utf-8")}return n},Zt=async e=>{try{return await ii(e),!0}catch{return!1}};import{readFile as ui}from"node:fs/promises";import di from"node:path";var nr=async e=>{let t=di.resolve(process.cwd(),e),r;try{r=await ui(t,"utf-8")}catch{throw new Error(`Config file not found: ${t}`)}let n=JSON.parse(r);if(typeof n!="object"||n===null||Array.isArray(n))throw new Error(`Config file ${t} must contain a JSON object`);if(n.options!==void 0&&(typeof n.options!="object"||n.options===null))throw new Error(`Config file ${t}: "options" must be an object`);return n},xe=e=>{let t={};for(let r of e??[]){let n=r.indexOf("=");if(n<=0)throw new Error(`--set expects key=value, got "${r}"`);t[r.slice(0,n).trim()]=r.slice(n+1).trim()}return t};var or={default:{description:"Manifest defaults: Redux, fetch, i18n, dark mode, unit + e2e tests, hooks",answers:{}},minimal:{description:"No state store, no i18n, no dark mode, no tests, no hooks",answers:{state:"none",i18n:!1,darkMode:!1,tests:!1,e2e:!1,hooks:!1,commitizen:!1}},full:{description:"Everything on: WebSocket, both HTTP adapters, Docker, CI, analyzer, OpenAPI, templates",answers:{ws:!0,http:"both",docker:!0,ci:!0,analyzer:!0,openapi:!0,githubTemplates:!0,communityFiles:["CODE_OF_CONDUCT.md","CONTRIBUTING.md","SECURITY.md"]}},zustand:{description:"Defaults with Zustand instead of Redux",answers:{state:"zustand"}},spa:{description:"Client-heavy app: Zustand, Axios, no i18n, Docker and CI on",answers:{state:"zustand",http:"axios",i18n:!1,docker:!0,ci:!0}}},Fe=()=>Object.keys(or),Me=e=>{let t=or[e];if(!t)throw new Error(`Unknown preset "${e}". Valid: ${Fe().join(", ")}.`);return{...t.answers}};var Qe=new Set;function $t(e){return Qe.add(e),()=>Qe.delete(e)}function gn(e){let{logger:t=c=>console.error(c),exitOnCancel:r=process.env.NODE_ENV!=="test"}=e??{},n=!1,o=async()=>{let c=[...Qe];Qe.clear();for(let l of c)try{await l()}catch(p){t(`Cleanup failed: ${p instanceof Error?p.message:String(p)}`)}},s=()=>{if(n){r&&process.exit(130);return}n=!0;let c=Qe.size>0;o().then(()=>{console.log(""),t("Setup cancelled by user"),console.log(""),r&&process.exit(c?130:0)})},i=c=>{if(c!==null&&typeof c=="object"&&"code"in c&&c.code==="ERR_USE_AFTER_CLOSE"){s();return}if(c instanceof Error){t(`Uncaught exception: ${c.message}`);return}t(`Uncaught exception: ${String(c)}`)},a=c=>{if(c instanceof Error){t(`Unhandled promise rejection: ${c.message}`);return}t(`Unhandled promise rejection: ${String(c)}`)};return process.on("SIGINT",s),process.on("SIGTERM",s),process.on("uncaughtException",i),process.on("unhandledRejection",a),()=>{process.off("SIGINT",s),process.off("SIGTERM",s),process.off("uncaughtException",i),process.off("unhandledRejection",a)}}import z from"picocolors";var fi={reset:e=>e,red:z.red,green:z.green,yellow:z.yellow,blue:z.blue,cyan:z.cyan,magenta:z.magenta,white:z.white,gray:z.gray,bright:z.bold,dim:z.dim};function pe(e,t="reset"){let r=fi[t]??(n=>n);console.log(r(e))}function kt(e){pe(`\u2716 ${e}`,"red")}var b=kt;function hn(e){pe(`\u26A0 ${e}`,"yellow")}function m(e){pe(e)}function Pt(){console.log(""),pe("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557","cyan"),pe("\u2551 \u2551","cyan"),pe("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),pe("\u2551 \u2551","cyan"),pe("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D","cyan"),console.log("")}import gi from"ora";function St(e="",t){let r=gi({text:e,...t});return r.start(),r}var hi=e=>e.charAt(0).toUpperCase()+e.slice(1),G=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),$=e=>hi(G(e));import yi from"ora";var h=yi();import{execFile as wi}from"node:child_process";import{cp as yn,mkdir as xi,stat as bi}from"node:fs/promises";import Ze from"node:path";import{promisify as vi}from"node:util";import $i from"degit";var ki=vi(wi),wn="teispace/nextjs-starter",Et="v2.0.0-alpha.1",Pi="NEXT_MAKER_STARTER_PATH",Si=(e=Et)=>e==="main"?wn:`${wn}#${e}`,V=(e={})=>{let t=e.starterPath??process.env[Pi];return t?{kind:"local",location:Ze.resolve(t)}:{kind:"remote",location:Si(e.ref)}},Ei=new Set(["node_modules",".git",".next","coverage","playwright-report","test-results",".env"]),Tt=async(e,t={})=>{let r=t.source??V();if(r.kind==="local"){try{if(!(await bi(r.location)).isDirectory())throw new Error("not a directory")}catch{throw new Error(`Starter path ${r.location} is not a directory`)}return await Ti(r.location,e),r}return await $i(r.location,{cache:!1,force:!0,verbose:t.verbose??!1}).clone(e),r},Ti=async(e,t)=>{let r=null;try{let{stdout:n}=await ki("git",["-C",e,"ls-files","-z","--cached","--others","--exclude-standard"],{maxBuffer:67108864});r=n.split("\0").filter(Boolean)}catch{r=null}if(r===null){await yn(e,t,{recursive:!0,filter:n=>!Ei.has(Ze.basename(n))});return}for(let n of r){let o=Ze.join(t,n);await xi(Ze.dirname(o),{recursive:!0});try{await yn(Ze.join(e,n),o)}catch{}}};import{existsSync as sr}from"node:fs";import et from"node:fs/promises";import Ri from"node:path";var j=async e=>et.readFile(e,"utf-8"),P=async(e,t)=>{await et.mkdir(Ri.dirname(e),{recursive:!0}),await et.writeFile(e,t,"utf-8")};var xn=async e=>{sr(e)&&await et.unlink(e)},tt=async e=>{sr(e)&&await et.rm(e,{recursive:!0,force:!0})},bn=async(e,t)=>{let r=await j(e),n=JSON.parse(r),o=t(n);await P(e,JSON.stringify(o,null,2))},w=e=>sr(e);import{execFile as ji}from"node:child_process";import{promisify as Ci}from"node:util";var Oi=Ci(ji),te=(e,t)=>Oi("git",e,t?{cwd:t}:void 0);function Ai(e){let t=e.trim();if(!t||t.startsWith("-"))throw new Error(`Invalid git remote "${e}".`);if(!(/^https?:\/\/\S+$/.test(t)||/^git@[\w.-]+:\S+$/.test(t)||/^ssh:\/\/\S+$/.test(t)||/^[\w.-]+\/[\w.-]+$/.test(t)))throw new Error(`Invalid git remote "${e}". Expected an https/ssh URL or "owner/repo".`)}var Rt=async(e,t,r)=>{try{if(await te(["init"],e),await te(["add","."],e),await te(["commit","-m","Initial commit from @teispace/next-maker"],e),t&&(Ai(t),await te(["remote","add","origin",t],e),r)){await te(["fetch","origin"],e);let n="main";try{await te(["show-branch","origin/main"],e)}catch{try{await te(["show-branch","origin/master"],e),n="master"}catch{n="main"}}await te(["merge",`origin/${n}`,"--allow-unrelated-histories","-X","ours"],e),await te(["push","origin",`HEAD:${n}`],e)}}catch(n){console.warn("Failed to initialize git repository",n)}};import{execFile as Ii}from"node:child_process";import{promisify as Ni}from"node:util";var Fi=Ni(Ii),vn=(e,t,r)=>Fi(e,t,{cwd:r,maxBuffer:64*1024*1024}),Mi=e=>{let t=e;return(`${t.stdout??""}
12
12
  ${t.stderr??""}`.trim()||(t.message??String(e))).split(`
13
13
  `).filter(Boolean).slice(-12).join(`
14
- `)},Si=e=>{switch(e){case"pnpm":return["install","--no-frozen-lockfile"];case"yarn":return["install","--no-immutable"];default:return["install"]}},pe=async(e,t)=>{try{await un(t,Si(t),e)}catch(r){throw new Error(`Failed to install dependencies with ${t}:
15
- ${ki(r)}`,{cause:r})}},Et=async(e,t,r)=>{let n=t==="npm"?["run",r]:[r];try{await un(t,n,e)}catch(o){console.warn(`Warning: Failed to run script '${r}': ${o}`)}};import Ei from"enquirer";var{prompt:fn}=Ei,Ri=/^[a-z0-9-_]+$/,ji=/^\d+\.\d+\.\d+$/,gn=e=>Ri.test(e),hn=e=>ji.test(e),et=e=>{if(!gn(e))throw new Error(`Invalid project name "${e}". Use lowercase letters, digits, hyphens, and underscores only \u2014 no slashes, "..", or absolute paths.`)},le=(e,t={})=>{let r=t.projectName??e??"my-app";et(r);let n=t.version??"0.1.0";if(!hn(n))throw new Error(`Invalid version "${n}". Expected semver (e.g. 0.1.0).`);return{projectName:r,description:t.description??"A Next.js application",author:t.author??"Teispace",version:n,email:t.email??"support@example.com",gitRemote:t.gitRemote??"",pushToRemote:t.pushToRemote??!1,gitIssues:t.gitIssues??"",gitHomepage:t.gitHomepage??"",readme:t.readme??!0,copyEnv:t.copyEnv??!0}},yn=e=>e.state?.answers??e.enquirer?.answers??{},wn=async e=>{e!==void 0&&et(e);let t=await fn([{type:"input",name:"projectName",message:"What is the project name?",initial:e||"my-app",skip:!!e,validate:r=>gn(r)||"Project name must be lowercase and contain only alphanumeric characters, hyphens, and underscores."},{type:"input",name:"description",message:"Project description:",initial:"A Next.js application"},{type:"input",name:"author",message:"Author:",initial:"Teispace"},{type:"input",name:"version",message:"Version:",initial:"0.1.0",validate:r=>hn(r)||"Version must be a valid semantic version (x.y.z)."},{type:"input",name:"email",message:"Support email:",initial:"support@example.com"},{type:"input",name:"gitRemote",message:"GitHub repository URL (optional):",initial:"",validate:r=>!r||/^(https:\/\/github\.com\/[\w-]+\/[\w.-]+(\.git)?|git@github\.com:[\w-]+\/[\w.-]+\.git)$/.test(r)||"Enter a GitHub URL (https://github.com/user/repo or git@github.com:user/repo.git)."},{type:"confirm",name:"pushToRemote",message:"Push the initial commit to the remote?",initial:!1,skip:function(){return!yn(this).gitRemote}},{type:"confirm",name:"readme",message:"Create a README.md?",initial:!0},{type:"confirm",name:"copyEnv",message:"Copy .env.example to .env?",initial:!0}]);return le(e,{...t,projectName:e??t.projectName})},Rt=async(e,t={})=>{let r=Object.entries(e.options).map(([s,i])=>{let a=t[s]??i.default,p={name:s,message:i.label??s,skip:function(){if(!i.requires)return!1;let c=yn(this);return!Object.entries(i.requires).every(([d,u])=>yt(e.options[d],c[d],u))}};if(i.type==="boolean")return{...p,type:"confirm",initial:!!a};if(i.type==="multi")return{...p,type:"multiselect",choices:(i.values??[]).map(c=>({name:c,value:c})),initial:Array.isArray(a)?a:[]};let m=i.values??[];return{...p,type:"select",choices:m,initial:Math.max(0,m.indexOf(String(a)))}}),n=await fn(r),o={};for(let[s,i]of Object.entries(e.options)){let a=n[s];a!==void 0&&(o[s]=i.type==="multi"&&!Array.isArray(a)?[]:a)}return o};import Ci from"node:path";var C={NEXT_CONFIG:"next.config.ts",POSTCSS_CONFIG:"postcss.config.mjs",BIOME_CONFIG:"biome.json",VITEST_CONFIG:"vitest.config.ts",TEST_DIR:"test",TS_CONFIG:"tsconfig.json",PACKAGE_JSON:"package.json",ENV_EXAMPLE:".env.example",GITIGNORE:".gitignore",README:"README.md",LICENSE:"LICENSE",CHANGELOG:"CHANGELOG.md",NVM_RC:".nvmrc",NPM_RC:".npmrc",AGENTS_MD:"AGENTS.md",CLAUDE_MD:"CLAUDE.md",SRC:"src",APP:"src/app",COMPONENTS:"src/components",LIB:"src/lib",PROVIDERS:"src/providers",STYLES:"src/styles",TYPES:"src/types",UTILS:"src/lib/utils",HOOKS:"src/hooks",SERVICES:"src/services",STORE:"src/store",I18N:"src/i18n",GLOBALS_CSS:"src/styles/globals.css",ROOT_LAYOUT:"src/app/layout.tsx",ROOT_PAGE:"src/app/page.tsx",ROOT_PROVIDER:"src/providers/RootProvider.tsx",PROVIDERS_INDEX:"src/providers/index.ts",COMPONENTS_INDEX:"src/components/index.ts",TYPES_INDEX:"src/types/index.ts",UTILS_INDEX:"src/lib/utils/index.ts",CONFIG_INDEX:"src/lib/config/index.ts",CONSTANTS:"src/lib/config/constants.ts",APP_LOCALES:"src/lib/config/app-locales.ts",SEO_FILE:"src/lib/config/seo.ts",SITEMAP_FILE:"src/app/sitemap.ts",MIDDLEWARE:"src/middleware.ts",PROXY:"src/proxy.ts",I18N_TYPES:"src/types/i18n.ts",HTTP_UTILS:"src/lib/utils/http",HTTP_SHARED:"src/lib/utils/http/shared",HTTP_SERVER_FILE:"src/lib/utils/http/server.ts",HTTP_BUNDLE_SENTINEL_DIR:"src/lib/utils/http/__bundle-sentinel__",HTTP_BUNDLE_SENTINEL_FILE:"src/lib/utils/http/__bundle-sentinel__/client-bundle-sentinel.tsx",WS_UTILS:"src/lib/utils/ws",WS_SLICE_FILE:"src/store/slices/ws.slice.ts",WS_SLICE_TEST_FILE:"src/store/slices/ws.slice.test.ts",ROOT_REDUCER:"src/store/rootReducer.ts",TEST_SETUP_FILE:"test/setup.ts",AXIOS_CLIENT:"src/lib/utils/http/axios-client",FETCH_CLIENT:"src/lib/utils/http/fetch-client",AXIOS_CLIENT_FILE:"src/lib/utils/http/axios-client/index.ts",FETCH_CLIENT_FILE:"src/lib/utils/http/fetch-client/index.ts",CLIENT_UTILS:"src/lib/utils/http/client-utils.ts",APP_APIS:"src/lib/config/app-apis.ts",API_URL_FILE:"src/lib/config/api-url.ts",STORAGE_SERVICE:"src/services/storage",COUNTER_FEATURE:"src/features/counter",I18N_DIR:"src/i18n",LOCALE_DIR:"src/app/[locale]",ERRORS_DIR:"src/lib/errors",UTILITY_TYPES_DIR:"src/types/utility",COMMON_TYPES_DIR:"src/types/common",HTTP_TYPES:"src/types/common/http.types.ts",GITHUB_DIR:".github",HUSKY_DIR:".husky",STORE_PROVIDER:"src/providers/StoreProvider.tsx",THEME_PROVIDER:"src/providers/CustomThemeProvider.tsx",COUNTER_COMPONENT:"src/features/counter/components/Counter.tsx",LOCALE_PAGE:"src/app/[locale]/page.tsx",LOCALE_LAYOUT:"src/app/[locale]/layout.tsx",COMMITLINT_CONFIG:"commitlint.config.mjs",LINTSTAGED_RC:".lintstagedrc.mjs",CZRC:".czrc",DOCKERIGNORE:".dockerignore",DOCKERFILE:"Dockerfile",DOCKER_COMPOSE:"docker-compose.yml",GITHUB_WORKFLOWS:".github/workflows",GITHUB_ISSUE_TEMPLATE:"ISSUE_TEMPLATE",GITHUB_PR_TEMPLATE:"PULL_REQUEST_TEMPLATE.md",CODE_OF_CONDUCT:"CODE_OF_CONDUCT.md",CONTRIBUTING:"CONTRIBUTING.md",SECURITY:"SECURITY.md",SCRIPTS_DIR:"scripts",DOCS_DIR:"docs",CLAUDE_DIR:".claude",VSCODE_DIR:".vscode"};var Ti=e=>{let t=e.gitRemote,r=e.gitHomepage,n=e.gitIssues;if(!t)return{remote:"",homepage:"",issues:""};t.startsWith("git@github.com:")&&(t=t.replace("git@github.com:","https://github.com/").replace(/\.git$/,""));let o=t.replace(/\.git$/,"");return r||=`${o}#readme`,n||=`${o}/issues`,t.endsWith(".git")||(t=`${t}.git`),{remote:t,homepage:r,issues:n}},xn=async(e,t)=>{let{remote:r,homepage:n,issues:o}=Ti(t);await dn(Ci.join(e,C.PACKAGE_JSON),s=>(s.name=t.projectName,s.version=t.version,s.description=t.description,s.author=t.author,delete s.keywords,r?(s.homepage=n,s.bugs={url:o},s.repository={type:"git",url:r}):(delete s.homepage,delete s.bugs,delete s.repository),s))};import{readdir as _i}from"node:fs/promises";import de from"node:path";import{cp as Oi,mkdir as Ai,mkdtemp as Ii,readFile as we,rm as $n,writeFile as jt}from"node:fs/promises";import{tmpdir as Ni}from"node:os";import O from"node:path";var Fe=".next-maker.json",me=async(e,t)=>{await jt(O.join(e,Fe),`${JSON.stringify(t,null,2)}
16
- `,"utf-8")},ee=async e=>{let t=O.join(e,Fe);if(!y(t))throw new Error(`No ${Fe} in ${e}. Only projects created with next-maker 5+ can be reconfigured; run \`next-maker init\` for a new project.`);return JSON.parse(await we(t,"utf-8"))},Me=async(e,t={})=>{let r=e.starter.source.startsWith("/")&&y(e.starter.source)?e.starter.source:void 0,n=B({starterPath:t.starterPath??r}),o=await Ii(O.join(Ni(),"next-maker-starter-"));await kt(o,{source:n});let s=await He(o),i=await L(o);return{dir:o,source:n,manifest:s,files:i,dispose:()=>$n(o,{recursive:!0,force:!0})}},bn=(e,t)=>e[t]??{},Fi=e=>[...e.off?.anchors??[],...e.on?.anchors??[]],Mi=async(e,t)=>{if(t.length===0)return[];let r=[],n=new RegExp(`@next-maker:(?:${t.map(o=>o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("|")})(?::(start|end))?`);for(let o of e.files){if(o.startsWith(".next-maker/"))continue;let s;try{s=await we(O.join(e.dir,o),"utf-8")}catch{continue}if(!Je(s))continue;let i=s.split(`
17
- `),a=[];for(let p=0;p<i.length;p++){let m=i[p].match(n);if(m)if(m[1]==="start"){let c=p+1;for(;c<i.length&&!/@next-maker:[\w-]+:end/.test(i[c]);)a.push(i[c++]);p=c}else m[1]==="end"||(/^\s*(\{\s*\/\*|\/\*|\/\/|#)/.test(i[p])?i[p+1]!==void 0&&a.push(i[++p]):a.push(i[p].replace(/\s*(\{\s*\/\*|\/\*|\/\/|#).*$/,"")))}a.length&&r.push({file:o,lines:a})}return r},Pn=async(e,t)=>{let r=e.manifest.features[t];if(!r)throw new Error(`Unknown feature "${t}". Valid: ${Object.keys(e.manifest.features).join(", ")}.`);let n=bn(r,"off"),o=bn(r,"on"),s=new Set(e.manifest.always.remove.flatMap(p=>se(e.files,p))),i=[...new Set((n.remove??[]).flatMap(p=>se(e.files,p)))].filter(p=>!s.has(p)).sort(),a=o.overlay?(await L(O.join(e.dir,ge,o.overlay),new Set)).sort():[];return{id:t,feature:r,files:i,overlayFiles:a,packages:n.packages??[],devPackages:n.devPackages??[],scripts:n.scripts??[],env:n.env??[],snippets:await Mi(e,Fi(r))}},kn=e=>/\.(test|spec)\.tsx?$/.test(e)||e.startsWith("test/")||e.includes("__test-utils__"),rr=async(e,t,r)=>{let n=JSON.parse(await we(O.join(e,"package.json"),"utf-8")),o=t.answers.tests!==!1,s=[],i=Object.values(r.manifest.features).filter(p=>!ie(r.manifest,p,t.answers)).flatMap(p=>p.off?.remove??[]),a=new Set(i.flatMap(p=>se(r.files,p)));for(let[p,m]of Object.entries(r.manifest.features)){let c=ie(r.manifest,m,t.answers);if(!c){s.push({id:p,on:c,drift:[]});continue}let d=await Pn(r,p),u=[];for(let f of[...d.files,...d.overlayFiles])!o&&kn(f)||a.has(f)||y(O.join(e,f))||u.push({kind:"missingFile",file:f});for(let f of d.packages)n.dependencies?.[f]||u.push({kind:"missingPackage",name:f,dev:!1});for(let f of d.devPackages)n.devDependencies?.[f]||u.push({kind:"missingPackage",name:f,dev:!0});for(let f of d.scripts)n.scripts?.[f]||u.push({kind:"missingScript",name:f});s.push({id:p,on:c,drift:u})}return s},Sn=async(e,t,r,n)=>{let o=t.answers,s=JSON.parse(await we(O.join(r.dir,"package.json"),"utf-8")),i=[],a=[];for(let[c,d]of Object.entries(r.manifest.features)){let u=ie(r.manifest,d,o),f=ie(r.manifest,d,n);u!==f&&(f?i:a).push(await Pn(r,c))}let p=n.tests!==!1,m={before:o,after:n,turningOn:i,turningOff:a,copy:[],remove:[],addPackages:{},addDevPackages:{},removePackages:[],addScripts:{},removeScripts:[],unwrapJsx:[],unwrapCall:[],manual:[]};for(let c of a){for(let d of[...c.files,...c.overlayFiles])y(O.join(e,d))&&m.remove.push(d);m.removePackages.push(...c.packages,...c.devPackages),m.removeScripts.push(...c.scripts),m.unwrapJsx.push(...c.feature.off?.unwrapJsx??[]),m.unwrapCall.push(...c.feature.off?.unwrapCall??[]),c.snippets.length&&m.manual.push({feature:c.id,direction:"delete",snippets:c.snippets})}for(let c of i){for(let d of[...c.files,...c.overlayFiles])!p&&kn(d)||(!y(O.join(e,d))||c.overlayFiles.includes(d))&&m.copy.push(d);for(let d of c.packages)m.addPackages[d]=s.dependencies?.[d]??"latest";for(let d of c.devPackages)m.addDevPackages[d]=s.devDependencies?.[d]??"latest";for(let d of c.scripts)s.scripts?.[d]&&(m.addScripts[d]=s.scripts[d]);c.snippets.length&&m.manual.push({feature:c.id,direction:"add",snippets:c.snippets})}return m.copy=[...new Set(m.copy)].sort(),m.remove=[...new Set(m.remove)].sort(),m},En=async(e,t,r,n)=>{for(let i of r.remove)await $n(O.join(e,i),{force:!0});for(let i of r.copy){let a=r.turningOn.find(c=>c.overlayFiles.includes(i)),p=a?.feature.on?.overlay?O.join(t.dir,ge,a.feature.on.overlay,i):O.join(t.dir,i),m=O.join(e,i);await Ai(O.dirname(m),{recursive:!0}),await Oi(p,m,{force:!0})}for(let{file:i,tag:a}of r.unwrapJsx){let p=O.join(e,i);if(!y(p))continue;let m=await we(p,"utf-8"),c=ze(m,a);c!==m&&await jt(p,c,"utf-8")}for(let{file:i,name:a}of r.unwrapCall){let p=O.join(e,i);if(!y(p))continue;let m=await we(p,"utf-8"),c=We(m,a);c!==m&&await jt(p,c,"utf-8")}let o=O.join(e,"package.json"),s=JSON.parse(await we(o,"utf-8"));s.dependencies??={},s.devDependencies??={},s.scripts??={};for(let i of r.removePackages)delete s.dependencies[i],delete s.devDependencies[i];for(let i of r.removeScripts)delete s.scripts[i];Object.assign(s.dependencies,r.addPackages),Object.assign(s.devDependencies,r.addDevPackages),Object.assign(s.scripts,r.addScripts),s.dependencies=vn(s.dependencies),s.devDependencies=vn(s.devDependencies),await jt(o,`${JSON.stringify(s,null,2)}
18
- `,"utf-8"),await me(e,{...n,answers:r.after})},vn=e=>Object.fromEntries(Object.entries(e).sort(([t],[r])=>t.localeCompare(r)));var Di=(e,t)=>e.replace(/support@teispace\.com/g,t.email).replace(/Next\.js Starter/g,t.projectName).replace(/\[AUTHOR\]/g,t.author).replace(/\[COMPANY\]/g,t.author).replace(/\[EMAIL\]/g,t.email),Rn=async(e,t)=>{let r=[de.join(e,C.GITHUB_DIR,C.GITHUB_PR_TEMPLATE),de.join(e,C.CODE_OF_CONDUCT),de.join(e,C.CONTRIBUTING),de.join(e,C.SECURITY)],n=de.join(e,C.GITHUB_DIR,C.GITHUB_ISSUE_TEMPLATE);if(y(n))for(let o of await _i(n))r.push(de.join(n,o));for(let o of r){if(!y(o))continue;let s=await j(o),i=Di(s,t);i!==s&&await k(o,i)}},jn=async(e,t)=>{let r=de.join(e,C.ENV_EXAMPLE);if(!y(r))return;let n=await j(r);n=n.replace(/^CONTAINER_NAME=.*$/m,`CONTAINER_NAME=${t.projectName} # -public`),n=n.replace(/^IMAGE_NAME=.*$/m,`IMAGE_NAME=${t.projectName} # -public`),await k(r,n)},Li=(e,t,r)=>{let n=e.options[t];if(!n)return null;let o=n.label??t;return n.type==="boolean"?r?o:null:Array.isArray(r)?r.length?`${o}: ${r.join(", ")}`:null:r==="none"?null:`${o}: ${String(r)}`},Cn=async(e,t,r,n,o)=>{let s=de.join(e,C.README);if(!t.readme){await mn(s);return}let i=Object.entries(n).filter(([m])=>m!=="packageManager").map(([m,c])=>Li(r,m,c)).filter(m=>m!==null),a=[["dev","development server"],["build","production build"],["start","serve the production build"],["lint:fix","lint, format, and sort imports"],["type-check","route types + tsc"],["check:deprecated","fail on deprecated API usage"],["validate","every gate CI runs"]];n.tests&&a.push(["test","unit and component tests"]),n.e2e&&a.push(["test:e2e","Playwright against a production build"]);let p=`# ${t.projectName}
14
+ `)},_i=e=>{switch(e){case"pnpm":return["install","--no-frozen-lockfile"];case"yarn":return["install","--no-immutable"];default:return["install"]}},le=async(e,t)=>{try{await vn(t,_i(t),e)}catch(r){throw new Error(`Failed to install dependencies with ${t}:
15
+ ${Mi(r)}`,{cause:r})}},jt=async(e,t,r)=>{let n=t==="npm"?["run",r]:[r];try{await vn(t,n,e)}catch(o){console.warn(`Warning: Failed to run script '${r}': ${o}`)}};import Di from"enquirer";var{prompt:$n}=Di,Li=/^[a-z0-9-_]+$/,Ui=/^\d+\.\d+\.\d+$/,kn=e=>Li.test(e),Pn=e=>Ui.test(e),rt=e=>{if(!kn(e))throw new Error(`Invalid project name "${e}". Use lowercase letters, digits, hyphens, and underscores only \u2014 no slashes, "..", or absolute paths.`)},me=(e,t={})=>{let r=t.projectName??e??"my-app";rt(r);let n=t.version??"0.1.0";if(!Pn(n))throw new Error(`Invalid version "${n}". Expected semver (e.g. 0.1.0).`);return{projectName:r,description:t.description??"A Next.js application",author:t.author??"Teispace",version:n,email:t.email??"support@example.com",gitRemote:t.gitRemote??"",pushToRemote:t.pushToRemote??!1,gitIssues:t.gitIssues??"",gitHomepage:t.gitHomepage??"",readme:t.readme??!0,copyEnv:t.copyEnv??!0}},Sn=e=>e.state?.answers??e.enquirer?.answers??{},En=async e=>{e!==void 0&&rt(e);let t=await $n([{type:"input",name:"projectName",message:"What is the project name?",initial:e||"my-app",skip:!!e,validate:r=>kn(r)||"Project name must be lowercase and contain only alphanumeric characters, hyphens, and underscores."},{type:"input",name:"description",message:"Project description:",initial:"A Next.js application"},{type:"input",name:"author",message:"Author:",initial:"Teispace"},{type:"input",name:"version",message:"Version:",initial:"0.1.0",validate:r=>Pn(r)||"Version must be a valid semantic version (x.y.z)."},{type:"input",name:"email",message:"Support email:",initial:"support@example.com"},{type:"input",name:"gitRemote",message:"GitHub repository URL (optional):",initial:"",validate:r=>!r||/^(https:\/\/github\.com\/[\w-]+\/[\w.-]+(\.git)?|git@github\.com:[\w-]+\/[\w.-]+\.git)$/.test(r)||"Enter a GitHub URL (https://github.com/user/repo or git@github.com:user/repo.git)."},{type:"confirm",name:"pushToRemote",message:"Push the initial commit to the remote?",initial:!1,skip:function(){return!Sn(this).gitRemote}},{type:"confirm",name:"readme",message:"Create a README.md?",initial:!0},{type:"confirm",name:"copyEnv",message:"Copy .env.example to .env?",initial:!0}]);return me(e,{...t,projectName:e??t.projectName})},Ct=async(e,t={})=>{let r=Object.entries(e.options).map(([s,i])=>{let a=t[s]??i.default,c={name:s,message:i.label??s,skip:function(){if(!i.requires)return!1;let p=Sn(this);return!Object.entries(i.requires).every(([u,f])=>bt(e.options[u],p[u],f))}};if(i.type==="boolean")return{...c,type:"confirm",initial:!!a};if(i.type==="multi")return{...c,type:"multiselect",choices:(i.values??[]).map(p=>({name:p,value:p})),initial:Array.isArray(a)?a:[]};let l=i.values??[];return{...c,type:"select",choices:l,initial:Math.max(0,l.indexOf(String(a)))}}),n=await $n(r),o={};for(let[s,i]of Object.entries(e.options)){let a=n[s];a!==void 0&&(o[s]=i.type==="multi"&&!Array.isArray(a)?[]:a)}return o};import Gi from"node:path";var C={NEXT_CONFIG:"next.config.ts",POSTCSS_CONFIG:"postcss.config.mjs",BIOME_CONFIG:"biome.json",VITEST_CONFIG:"vitest.config.ts",TEST_DIR:"test",TS_CONFIG:"tsconfig.json",PACKAGE_JSON:"package.json",ENV_EXAMPLE:".env.example",GITIGNORE:".gitignore",README:"README.md",LICENSE:"LICENSE",CHANGELOG:"CHANGELOG.md",NVM_RC:".nvmrc",NPM_RC:".npmrc",AGENTS_MD:"AGENTS.md",CLAUDE_MD:"CLAUDE.md",SRC:"src",APP:"src/app",COMPONENTS:"src/components",LIB:"src/lib",PROVIDERS:"src/providers",STYLES:"src/styles",TYPES:"src/types",UTILS:"src/lib/utils",HOOKS:"src/hooks",SERVICES:"src/services",STORE:"src/store",I18N:"src/i18n",GLOBALS_CSS:"src/styles/globals.css",ROOT_LAYOUT:"src/app/layout.tsx",ROOT_PAGE:"src/app/page.tsx",ROOT_PROVIDER:"src/providers/RootProvider.tsx",PROVIDERS_INDEX:"src/providers/index.ts",COMPONENTS_INDEX:"src/components/index.ts",TYPES_INDEX:"src/types/index.ts",UTILS_INDEX:"src/lib/utils/index.ts",CONFIG_INDEX:"src/lib/config/index.ts",CONSTANTS:"src/lib/config/constants.ts",APP_LOCALES:"src/lib/config/app-locales.ts",SEO_FILE:"src/lib/config/seo.ts",SITEMAP_FILE:"src/app/sitemap.ts",MIDDLEWARE:"src/middleware.ts",PROXY:"src/proxy.ts",I18N_TYPES:"src/types/i18n.ts",HTTP_UTILS:"src/lib/utils/http",HTTP_SHARED:"src/lib/utils/http/shared",HTTP_SERVER_FILE:"src/lib/utils/http/server.ts",HTTP_BUNDLE_SENTINEL_DIR:"src/lib/utils/http/__bundle-sentinel__",HTTP_BUNDLE_SENTINEL_FILE:"src/lib/utils/http/__bundle-sentinel__/client-bundle-sentinel.tsx",WS_UTILS:"src/lib/utils/ws",WS_SLICE_FILE:"src/store/slices/ws.slice.ts",WS_SLICE_TEST_FILE:"src/store/slices/ws.slice.test.ts",ROOT_REDUCER:"src/store/rootReducer.ts",TEST_SETUP_FILE:"test/setup.ts",AXIOS_CLIENT:"src/lib/utils/http/axios-client",FETCH_CLIENT:"src/lib/utils/http/fetch-client",AXIOS_CLIENT_FILE:"src/lib/utils/http/axios-client/index.ts",FETCH_CLIENT_FILE:"src/lib/utils/http/fetch-client/index.ts",CLIENT_UTILS:"src/lib/utils/http/client-utils.ts",APP_APIS:"src/lib/config/app-apis.ts",API_URL_FILE:"src/lib/config/api-url.ts",STORAGE_SERVICE:"src/services/storage",COUNTER_FEATURE:"src/features/counter",I18N_DIR:"src/i18n",LOCALE_DIR:"src/app/[locale]",ERRORS_DIR:"src/lib/errors",UTILITY_TYPES_DIR:"src/types/utility",COMMON_TYPES_DIR:"src/types/common",HTTP_TYPES:"src/types/common/http.types.ts",GITHUB_DIR:".github",HUSKY_DIR:".husky",STORE_PROVIDER:"src/providers/StoreProvider.tsx",THEME_PROVIDER:"src/providers/CustomThemeProvider.tsx",COUNTER_COMPONENT:"src/features/counter/components/Counter.tsx",LOCALE_PAGE:"src/app/[locale]/page.tsx",LOCALE_LAYOUT:"src/app/[locale]/layout.tsx",COMMITLINT_CONFIG:"commitlint.config.mjs",LINTSTAGED_RC:".lintstagedrc.mjs",CZRC:".czrc",DOCKERIGNORE:".dockerignore",DOCKERFILE:"Dockerfile",DOCKER_COMPOSE:"docker-compose.yml",GITHUB_WORKFLOWS:".github/workflows",GITHUB_ISSUE_TEMPLATE:"ISSUE_TEMPLATE",GITHUB_PR_TEMPLATE:"PULL_REQUEST_TEMPLATE.md",CODE_OF_CONDUCT:"CODE_OF_CONDUCT.md",CONTRIBUTING:"CONTRIBUTING.md",SECURITY:"SECURITY.md",SCRIPTS_DIR:"scripts",DOCS_DIR:"docs",CLAUDE_DIR:".claude",VSCODE_DIR:".vscode"};var Bi=e=>{let t=e.gitRemote,r=e.gitHomepage,n=e.gitIssues;if(!t)return{remote:"",homepage:"",issues:""};t.startsWith("git@github.com:")&&(t=t.replace("git@github.com:","https://github.com/").replace(/\.git$/,""));let o=t.replace(/\.git$/,"");return r||=`${o}#readme`,n||=`${o}/issues`,t.endsWith(".git")||(t=`${t}.git`),{remote:t,homepage:r,issues:n}},Tn=async(e,t)=>{let{remote:r,homepage:n,issues:o}=Bi(t);await bn(Gi.join(e,C.PACKAGE_JSON),s=>(s.name=t.projectName,s.version=t.version,s.description=t.description,s.author=t.author,delete s.keywords,r?(s.homepage=n,s.bugs={url:o},s.repository={type:"git",url:r}):(delete s.homepage,delete s.bugs,delete s.repository),s))};import{readdir as Ki}from"node:fs/promises";import de from"node:path";import{cp as Vi,mkdir as Hi,mkdtemp as qi,readFile as be,rm as Cn,writeFile as Ot}from"node:fs/promises";import{tmpdir as Ji}from"node:os";import A from"node:path";var _e=".next-maker.json",ue=async(e,t)=>{await Ot(A.join(e,_e),`${JSON.stringify(t,null,2)}
16
+ `,"utf-8")},re=async e=>{let t=A.join(e,_e);if(!w(t))throw new Error(`No ${_e} in ${e}. Only projects created with next-maker 5+ can be reconfigured; run \`next-maker init\` for a new project.`);return JSON.parse(await be(t,"utf-8"))},De=async(e,t={})=>{let r=e.starter.source.startsWith("/")&&w(e.starter.source)?e.starter.source:void 0,n=V({starterPath:t.starterPath??r}),o=await qi(A.join(Ji(),"next-maker-starter-"));await Tt(o,{source:n});let s=await Xe(o),i=await L(o);return{dir:o,source:n,manifest:s,files:i,dispose:()=>Cn(o,{recursive:!0,force:!0})}},Rn=(e,t)=>e[t]??{},zi=e=>[...e.off?.anchors??[],...e.on?.anchors??[]],Wi=async(e,t)=>{if(t.length===0)return[];let r=[],n=new RegExp(`@next-maker:(?:${t.map(o=>o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("|")})(?::(start|end))?`);for(let o of e.files){if(o.startsWith(".next-maker/"))continue;let s;try{s=await be(A.join(e.dir,o),"utf-8")}catch{continue}if(!ze(s))continue;let i=s.split(`
17
+ `),a=[];for(let c=0;c<i.length;c++){let l=i[c].match(n);if(l)if(l[1]==="start"){let p=c+1;for(;p<i.length&&!/@next-maker:[\w-]+:end/.test(i[p]);)a.push(i[p++]);c=p}else l[1]==="end"||(/^\s*(\{\s*\/\*|\/\*|\/\/|#)/.test(i[c])?i[c+1]!==void 0&&a.push(i[++c]):a.push(i[c].replace(/\s*(\{\s*\/\*|\/\*|\/\/|#).*$/,"")))}a.length&&r.push({file:o,lines:a})}return r},On=async(e,t)=>{let r=e.manifest.features[t];if(!r)throw new Error(`Unknown feature "${t}". Valid: ${Object.keys(e.manifest.features).join(", ")}.`);let n=Rn(r,"off"),o=Rn(r,"on"),s=new Set(e.manifest.always.remove.flatMap(c=>ie(e.files,c))),i=[...new Set((n.remove??[]).flatMap(c=>ie(e.files,c)))].filter(c=>!s.has(c)).sort(),a=o.overlay?(await L(A.join(e.dir,ye,o.overlay),new Set)).sort():[];return{id:t,feature:r,files:i,overlayFiles:a,packages:n.packages??[],devPackages:n.devPackages??[],scripts:n.scripts??[],env:n.env??[],snippets:await Wi(e,zi(r))}},An=e=>/\.(test|spec)\.tsx?$/.test(e)||e.startsWith("test/")||e.includes("__test-utils__"),ir=async(e,t,r)=>{let n=JSON.parse(await be(A.join(e,"package.json"),"utf-8")),o=t.answers.tests!==!1,s=[],i=Object.values(r.manifest.features).filter(c=>!ae(r.manifest,c,t.answers)).flatMap(c=>c.off?.remove??[]),a=new Set(i.flatMap(c=>ie(r.files,c)));for(let[c,l]of Object.entries(r.manifest.features)){let p=ae(r.manifest,l,t.answers);if(!p){s.push({id:c,on:p,drift:[]});continue}let u=await On(r,c),f=[];for(let d of[...u.files,...u.overlayFiles])!o&&An(d)||a.has(d)||w(A.join(e,d))||f.push({kind:"missingFile",file:d});for(let d of u.packages)n.dependencies?.[d]||f.push({kind:"missingPackage",name:d,dev:!1});for(let d of u.devPackages)n.devDependencies?.[d]||f.push({kind:"missingPackage",name:d,dev:!0});for(let d of u.scripts)n.scripts?.[d]||f.push({kind:"missingScript",name:d});s.push({id:c,on:p,drift:f})}return s},In=async(e,t,r,n)=>{let o=t.answers,s=JSON.parse(await be(A.join(r.dir,"package.json"),"utf-8")),i=[],a=[];for(let[p,u]of Object.entries(r.manifest.features)){let f=ae(r.manifest,u,o),d=ae(r.manifest,u,n);f!==d&&(d?i:a).push(await On(r,p))}let c=n.tests!==!1,l={before:o,after:n,turningOn:i,turningOff:a,copy:[],remove:[],addPackages:{},addDevPackages:{},removePackages:[],addScripts:{},removeScripts:[],unwrapJsx:[],unwrapCall:[],manual:[]};for(let p of a){for(let u of[...p.files,...p.overlayFiles])w(A.join(e,u))&&l.remove.push(u);l.removePackages.push(...p.packages,...p.devPackages),l.removeScripts.push(...p.scripts),l.unwrapJsx.push(...p.feature.off?.unwrapJsx??[]),l.unwrapCall.push(...p.feature.off?.unwrapCall??[]),p.snippets.length&&l.manual.push({feature:p.id,direction:"delete",snippets:p.snippets})}for(let p of i){for(let u of[...p.files,...p.overlayFiles])!c&&An(u)||(!w(A.join(e,u))||p.overlayFiles.includes(u))&&l.copy.push(u);for(let u of p.packages)l.addPackages[u]=s.dependencies?.[u]??"latest";for(let u of p.devPackages)l.addDevPackages[u]=s.devDependencies?.[u]??"latest";for(let u of p.scripts)s.scripts?.[u]&&(l.addScripts[u]=s.scripts[u]);p.snippets.length&&l.manual.push({feature:p.id,direction:"add",snippets:p.snippets})}return l.copy=[...new Set(l.copy)].sort(),l.remove=[...new Set(l.remove)].sort(),l},Nn=async(e,t,r,n)=>{for(let i of r.remove)await Cn(A.join(e,i),{force:!0});for(let i of r.copy){let a=r.turningOn.find(p=>p.overlayFiles.includes(i)),c=a?.feature.on?.overlay?A.join(t.dir,ye,a.feature.on.overlay,i):A.join(t.dir,i),l=A.join(e,i);await Hi(A.dirname(l),{recursive:!0}),await Vi(c,l,{force:!0})}for(let{file:i,tag:a}of r.unwrapJsx){let c=A.join(e,i);if(!w(c))continue;let l=await be(c,"utf-8"),p=We(l,a);p!==l&&await Ot(c,p,"utf-8")}for(let{file:i,name:a}of r.unwrapCall){let c=A.join(e,i);if(!w(c))continue;let l=await be(c,"utf-8"),p=Ke(l,a);p!==l&&await Ot(c,p,"utf-8")}let o=A.join(e,"package.json"),s=JSON.parse(await be(o,"utf-8"));s.dependencies??={},s.devDependencies??={},s.scripts??={};for(let i of r.removePackages)delete s.dependencies[i],delete s.devDependencies[i];for(let i of r.removeScripts)delete s.scripts[i];Object.assign(s.dependencies,r.addPackages),Object.assign(s.devDependencies,r.addDevPackages),Object.assign(s.scripts,r.addScripts),s.dependencies=jn(s.dependencies),s.devDependencies=jn(s.devDependencies),await Ot(o,`${JSON.stringify(s,null,2)}
18
+ `,"utf-8"),await ue(e,{...n,answers:r.after})},jn=e=>Object.fromEntries(Object.entries(e).sort(([t],[r])=>t.localeCompare(r)));var Xi=(e,t)=>e.replace(/support@teispace\.com/g,t.email).replace(/Next\.js Starter/g,t.projectName).replace(/\[AUTHOR\]/g,t.author).replace(/\[COMPANY\]/g,t.author).replace(/\[EMAIL\]/g,t.email),Fn=async(e,t)=>{let r=[de.join(e,C.GITHUB_DIR,C.GITHUB_PR_TEMPLATE),de.join(e,C.CODE_OF_CONDUCT),de.join(e,C.CONTRIBUTING),de.join(e,C.SECURITY)],n=de.join(e,C.GITHUB_DIR,C.GITHUB_ISSUE_TEMPLATE);if(w(n))for(let o of await Ki(n))r.push(de.join(n,o));for(let o of r){if(!w(o))continue;let s=await j(o),i=Xi(s,t);i!==s&&await P(o,i)}},Mn=async(e,t)=>{let r=de.join(e,C.ENV_EXAMPLE);if(!w(r))return;let n=await j(r);n=n.replace(/^CONTAINER_NAME=.*$/m,`CONTAINER_NAME=${t.projectName} # -public`),n=n.replace(/^IMAGE_NAME=.*$/m,`IMAGE_NAME=${t.projectName} # -public`),await P(r,n)},Yi=(e,t,r)=>{let n=e.options[t];if(!n)return null;let o=n.label??t;return n.type==="boolean"?r?o:null:Array.isArray(r)?r.length?`${o}: ${r.join(", ")}`:null:r==="none"?null:`${o}: ${String(r)}`},_n=async(e,t,r,n,o)=>{let s=de.join(e,C.README);if(!t.readme){await xn(s);return}let i=Object.entries(n).filter(([l])=>l!=="packageManager").map(([l,p])=>Yi(r,l,p)).filter(l=>l!==null),a=[["dev","development server"],["build","production build"],["start","serve the production build"],["lint:fix","lint, format, and sort imports"],["type-check","route types + tsc"],["check:deprecated","fail on deprecated API usage"],["validate","every gate CI runs"]];n.tests&&a.push(["test","unit and component tests"]),n.e2e&&a.push(["test:e2e","Playwright against a production build"]);let c=`# ${t.projectName}
19
19
 
20
20
  ${t.description}
21
21
 
@@ -25,21 +25,21 @@ Generated from [@teispace/nextjs-starter](https://github.com/teispace/nextjs-sta
25
25
 
26
26
  \`\`\`bash
27
27
  ${o} install
28
- ${ae(o,"dev")}
28
+ ${ce(o,"dev")}
29
29
  \`\`\`
30
30
 
31
- Open [http://localhost:3000](http://localhost:3000). Copy \`.env.example\` to \`.env\` and set \`NEXT_PUBLIC_API_URL\` to your API origin.
31
+ Open [http://localhost:3000](http://localhost:3000). Copy \`.env.example\` to \`.env\` and set \`NEXT_PUBLIC_API_URL\` to your API origin. Production builds also need \`NEXT_PUBLIC_APP_URL\`, the public URL of this app.
32
32
 
33
33
  ## What is included
34
34
 
35
- ${i.map(m=>`- ${m}`).join(`
35
+ ${i.map(l=>`- ${l}`).join(`
36
36
  `)}
37
37
 
38
38
  ## Scripts
39
39
 
40
40
  | Script | Purpose |
41
41
  | :-- | :-- |
42
- ${a.map(([m,c])=>`| \`${ae(o,m)}\` | ${c} |`).join(`
42
+ ${a.map(([l,p])=>`| \`${ce(o,l)}\` | ${p} |`).join(`
43
43
  `)}
44
44
 
45
45
  ## Guides
@@ -51,9 +51,9 @@ ${a.map(([m,c])=>`| \`${ae(o,m)}\` | ${c} |`).join(`
51
51
  ${n.ws?"- `src/lib/ws/README.md`: the WebSocket client\n":""}${n.i18n?"- `src/i18n/README.md`: internationalization\n":""}- \`docs/ui-libraries.md\`: adding shadcn/ui, Radix, MUI, Mantine, or HeroUI
52
52
 
53
53
  Generators: \`npx @teispace/next-maker feature <name>\`, \`page <name>\`, \`component <name>\`, \`env <NAME>\`${n.i18n?", `locale <code>`":""}.
54
- `;await k(s,p)};var xe=async e=>{await kt(e.projectPath,{source:e.source});let t=await He(e.projectPath);return tt(t,e.supplied,e.packageManager)},tt=(e,t,r)=>{let{answers:n,forced:o,unknown:s}=Ke(e,t),i=n.packageManager??r??"pnpm";return{manifest:e,answers:n,forced:o,unknown:s,packageManager:i,plan:Xt(e,n,i)}},be=async(e,t,r,n)=>{let{manifest:o,answers:s,packageManager:i,plan:a}=r,p=await Qt(e,o,a);return await xn(e,t),await Rn(e,t),await jn(e,t),await Cn(e,t,o,s,i),await me(e,{cli:Te.version,starter:{name:o.starter.name,version:o.starter.version,source:n.location},packageManager:i,answers:s,identity:{projectName:t.projectName,description:t.description,author:t.author,version:t.version,email:t.email,gitRemote:t.gitRemote,readme:t.readme}}),p};var nr=["pnpm","npm","yarn","bun"],Gi=e=>{if(e!==void 0){if(!nr.includes(e))throw new Error(`Invalid --package-manager "${e}". Valid: ${nr.join(", ")}.`);return e}},Bi=(e,t=[])=>[...t,e],Tn=e=>{e.command("init").description("Create a new Next.js project from the Teispace starter").argument("[name]","Project name").option("-y, --yes","Skip every prompt and use the starter defaults").option("--preset <name>",`Start from a preset (${Ie().join(", ")})`).option("--config <file>","Read identity and options from a JSON file (non-interactive)").option("--set <key=value>","Override one starter option (repeatable), e.g. --set i18n=false",Bi).option("--package-manager <pm>",`Package manager (${nr.join(", ")})`).option("--starter-path <dir>","Compose from a local starter checkout instead of the pinned tag").option("--dry-run","Print the composition plan and create nothing").option("--no-install","Skip dependency installation").option("--no-git","Skip git init").action(async(t,r)=>{try{await zi(t,r)}catch(n){x(`${n instanceof Error?n.message:n}`),process.exit(1)}})},rt=async(e,t,r,n)=>{let o=$t(e);n.current=o;try{let s=await r();return o.succeed(t),s}finally{n.current===o&&(n.current=null)}},Vi=e=>Array.isArray(e)?e.length?e.join(", "):"none":String(e),qi=(e,t,r)=>{l(A.bold("Options"));for(let[n,o]of Object.entries(t.answers)){let s=e.options[n]?.label??n;l(` ${A.dim(s.padEnd(44))} ${Vi(o)}`)}for(let n of r)l(A.yellow(` ! ${n.reason}; ${n.option} turned off`));l(""),l(A.bold("Composition")),l(` ${A.green("keep")} ${t.featuresOn.join(", ")||"(none)"}`),l(` ${A.red("drop")} ${t.featuresOff.join(", ")||"(none)"}`),(t.featureOverlays.length||t.pmOverlays.length)&&l(` ${A.cyan("overlay")} ${[...t.pmOverlays,...t.featureOverlays].join(", ")}`),(t.packages.length||t.devPackages.length)&&l(` ${A.red("uninstall")} ${[...t.packages,...t.devPackages].join(", ")}`),l("")},Ji=async(e,t)=>{let r=t.config?await Zt(t.config):void 0,n=Gi(t.packageManager??r?.packageManager),s={...t.preset?Ne(t.preset):r?.preset?Ne(r.preset):{},...r?.options??{},...ye(t.set)};n&&(s.packageManager=n);let i=!(t.yes||r);return{identity:i?await wn(e):le(e,{projectName:r?.name,description:r?.description,author:r?.author,version:r?.version,email:r?.email,gitRemote:r?.gitRemote,readme:r?.readme,copyEnv:r?.copyEnv}),packageManager:n??"pnpm",suppliedOptions:s,interactive:i,install:t.install!==!1&&r?.install!==!1,git:t.git!==!1&&r?.git!==!1}},zi=async(e,t)=>{vt();let r=await Ji(e,t),{identity:n}=r,o=Ct.resolve(process.cwd(),n.projectName);if(y(o))throw new Error(`Directory ${n.projectName} already exists.`);let s={current:null},i=async()=>{y(o)&&(s.current?.stop(),s.current=null,l(A.yellow(`
55
- Cleaning up ${n.projectName}...`)),await Ze(o))},a=xt(async()=>{l(A.red(`
56
- Process interrupted.`)),await i()});try{let p=B({starterPath:t.starterPath}),m=await rt(`Fetching starter (${p.location})...`,"Starter fetched.",()=>xe({projectPath:o,source:p,supplied:r.suppliedOptions,packageManager:r.packageManager}),s);if(l(A.dim(` ${m.manifest.starter.name} ${m.manifest.starter.version}`)),l(""),r.interactive){let f={...r.suppliedOptions,...await Rt(m.manifest,m.answers)};t.packageManager&&(f.packageManager=t.packageManager),m=tt(m.manifest,f,r.packageManager),l("")}for(let f of m.unknown)l(A.yellow(` ! unknown option "${f}" ignored`));let{packageManager:c,plan:d,manifest:u}=m;if(qi(u,d,m.forced),t.dryRun){a(),await Ze(o),l(A.cyan("Dry run: nothing was created."));return}await rt("Composing project...","Project composed.",()=>be(o,n,m,p),s),r.install&&(await rt(`Installing dependencies with ${c}...`,"Dependencies installed.",()=>pe(o,c),s),await rt("Formatting...","Formatted.",()=>Et(o,c,"lint:fix"),s)),n.copyEnv&&y(Ct.join(o,".env.example"))&&await Ui(Ct.join(o,".env.example"),Ct.join(o,".env")),r.git&&await rt("Initializing git...","Git initialized.",()=>St(o,n.gitRemote,n.pushToRemote),s),a(),l(""),l(A.green(`\u2728 ${n.projectName} is ready.`)),l(""),l("Next:"),l(A.cyan(` cd ${n.projectName}`)),r.install||l(A.cyan(` ${c} install`)),l(A.cyan(` ${c==="pnpm"||c==="yarn"?`${c} dev`:`${c} run dev`}`)),l("")}catch(p){throw a(),s.current?.fail("Failed to create project."),s.current=null,await i(),p}};import Cr from"node:path";import K from"picocolors";import Tt from"node:path";var On=/^[A-Za-z][A-Za-z0-9-]*$/,Wi=/^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i;function An(e){return Wi.test(e)}function F(e,t="name"){let r=e?.trim();if(!r)throw new Error(`A ${t} is required.`);if(!On.test(r))throw new Error(`Invalid ${t} "${e}". Use letters, digits, and hyphens only \u2014 no slashes, spaces, "..", or absolute paths.`);if(An(r))throw new Error(`Invalid ${t} "${e}". That is a reserved name on Windows.`);return r}function W(e,t="path"){let r=e?.trim();if(!r)throw new Error(`A ${t} is required.`);let n=r.replace(/^\.\//,"");if(n.startsWith("/")||/^[a-zA-Z]:/.test(n))throw new Error(`Invalid ${t} "${e}". Must be a relative path inside the project (no leading "/" or drive letter).`);for(let o of n.split("/")){if(!On.test(o))throw new Error(`Invalid ${t} "${e}". Each segment must be kebab/camel-case (letters, digits, hyphens), separated by "/" \u2014 no "..", dots, or empty segments.`);if(An(o))throw new Error(`Invalid ${t} "${e}". Segment "${o}" is reserved on Windows.`)}return n}function te(e,...t){let r=Tt.resolve(e),n=Tt.resolve(r,...t),o=Tt.relative(r,n);if(o===""||o===".")return n;if(o.startsWith("..")||Tt.isAbsolute(o))throw new Error(`Refusing to write outside the project directory (resolved path escapes "${r}").`);return n}import{access as Hi}from"node:fs/promises";import Ki from"node:path";var ve=async(e,t,r)=>{try{return await Hi(Ki.join(e,r,t)),!0}catch{return!1}};import{access as Xi,readFile as Nn}from"node:fs/promises";import or from"node:path";var _e=async e=>{try{return await Xi(e),!0}catch{return!1}},In=async e=>{try{return JSON.parse(await Nn(e,"utf-8"))}catch{return null}},T=async e=>{let t=await In(or.join(e,"package.json"));if(!t)throw new Error(`Failed to detect project setup: no package.json in ${e}`);let r={...t.dependencies,...t.devDependencies},n=await In(or.join(e,Fe)),o=(...w)=>or.join(e,...w),s=await _e(o("src","store")),i=!!(r["@reduxjs/toolkit"]&&r["react-redux"])&&s,a=!!r.zustand&&s&&!i,p=i?"redux":a?"zustand":"none",m=await _e(o("src","lib","http","core","client.ts")),c=!!r.axios&&await _e(o("src","lib","http","adapters","axios.ts")),d="none";if(m)if(!c)d="fetch";else{let w="";try{w=await Nn(o("src","lib","http","client.ts"),"utf-8")}catch{}d=w.includes("axiosAdapter")?"axios":"both"}let u=!!r["next-intl"]&&await _e(o("src","i18n")),f=!!r.vitest||await _e(o("vitest.config.ts")),h=r["socket.io-client"]&&await _e(o("src","lib","ws"))?"present":"none";return{state:p,hasRedux:i,httpClient:d,hasI18n:u,hasTests:f,ws:h,hasQuery:!!r["@tanstack/react-query"],hasActions:!!r["next-safe-action"],record:n??void 0}};import{mkdir as Yi,writeFile as Qi}from"node:fs/promises";import sr from"node:path";var Fn=({pascalName:e,camelName:t})=>`import { z } from 'zod';
54
+ `;await P(s,c)};var ve=async e=>{await Tt(e.projectPath,{source:e.source});let t=await Xe(e.projectPath);return nt(t,e.supplied,e.packageManager)},nt=(e,t,r)=>{let{answers:n,forced:o,unknown:s}=Ye(e,t),i=n.packageManager??r??"pnpm";return{manifest:e,answers:n,forced:o,unknown:s,packageManager:i,plan:er(e,n,i)}},$e=async(e,t,r,n)=>{let{manifest:o,answers:s,packageManager:i,plan:a}=r,c=await rr(e,o,a);return await Tn(e,t),await Fn(e,t),await Mn(e,t),await _n(e,t,o,s,i),await ue(e,{cli:Ae.version,starter:{name:o.starter.name,version:o.starter.version,source:n.location},packageManager:i,answers:s,identity:{projectName:t.projectName,description:t.description,author:t.author,version:t.version,email:t.email,gitRemote:t.gitRemote,readme:t.readme}}),c};var ar=["pnpm","npm","yarn","bun"],Zi=e=>{if(e!==void 0){if(!ar.includes(e))throw new Error(`Invalid --package-manager "${e}". Valid: ${ar.join(", ")}.`);return e}},ea=(e,t=[])=>[...t,e],Dn=e=>{e.command("init").description("Create a new Next.js project from the Teispace starter").argument("[name]","Project name").option("-y, --yes","Skip every prompt and use the starter defaults").option("--preset <name>",`Start from a preset (${Fe().join(", ")})`).option("--config <file>","Read identity and options from a JSON file (non-interactive)").option("--set <key=value>","Override one starter option (repeatable), e.g. --set i18n=false",ea).option("--package-manager <pm>",`Package manager (${ar.join(", ")})`).option("--starter-path <dir>","Compose from a local starter checkout instead of the pinned tag").option("--dry-run","Print the composition plan and create nothing").option("--no-install","Skip dependency installation").option("--no-git","Skip git init").action(async(t,r)=>{try{await oa(t,r)}catch(n){b(`${n instanceof Error?n.message:n}`),process.exit(1)}})},ot=async(e,t,r,n)=>{let o=St(e);n.current=o;try{let s=await r();return o.succeed(t),s}finally{n.current===o&&(n.current=null)}},ta=e=>Array.isArray(e)?e.length?e.join(", "):"none":String(e),ra=(e,t,r)=>{m(I.bold("Options"));for(let[n,o]of Object.entries(t.answers)){let s=e.options[n]?.label??n;m(` ${I.dim(s.padEnd(44))} ${ta(o)}`)}for(let n of r)m(I.yellow(` ! ${n.reason}; ${n.option} turned off`));m(""),m(I.bold("Composition")),m(` ${I.green("keep")} ${t.featuresOn.join(", ")||"(none)"}`),m(` ${I.red("drop")} ${t.featuresOff.join(", ")||"(none)"}`),(t.featureOverlays.length||t.pmOverlays.length)&&m(` ${I.cyan("overlay")} ${[...t.pmOverlays,...t.featureOverlays].join(", ")}`),(t.packages.length||t.devPackages.length)&&m(` ${I.red("uninstall")} ${[...t.packages,...t.devPackages].join(", ")}`),m("")},na=async(e,t)=>{let r=t.config?await nr(t.config):void 0,n=Zi(t.packageManager??r?.packageManager),s={...t.preset?Me(t.preset):r?.preset?Me(r.preset):{},...r?.options??{},...xe(t.set)};n&&(s.packageManager=n);let i=!(t.yes||r);return{identity:i?await En(e):me(e,{projectName:r?.name,description:r?.description,author:r?.author,version:r?.version,email:r?.email,gitRemote:r?.gitRemote,readme:r?.readme,copyEnv:r?.copyEnv}),packageManager:n??"pnpm",suppliedOptions:s,interactive:i,install:t.install!==!1&&r?.install!==!1,git:t.git!==!1&&r?.git!==!1}},oa=async(e,t)=>{Pt();let r=await na(e,t),{identity:n}=r,o=At.resolve(process.cwd(),n.projectName);if(w(o))throw new Error(`Directory ${n.projectName} already exists.`);let s={current:null},i=async()=>{w(o)&&(s.current?.stop(),s.current=null,m(I.yellow(`
55
+ Cleaning up ${n.projectName}...`)),await tt(o))},a=$t(async()=>{m(I.red(`
56
+ Process interrupted.`)),await i()});try{let c=V({starterPath:t.starterPath}),l=await ot(`Fetching starter (${c.location})...`,"Starter fetched.",()=>ve({projectPath:o,source:c,supplied:r.suppliedOptions,packageManager:r.packageManager}),s);if(m(I.dim(` ${l.manifest.starter.name} ${l.manifest.starter.version}`)),m(""),r.interactive){let d={...r.suppliedOptions,...await Ct(l.manifest,l.answers)};t.packageManager&&(d.packageManager=t.packageManager),l=nt(l.manifest,d,r.packageManager),m("")}for(let d of l.unknown)m(I.yellow(` ! unknown option "${d}" ignored`));let{packageManager:p,plan:u,manifest:f}=l;if(ra(f,u,l.forced),t.dryRun){a(),await tt(o),m(I.cyan("Dry run: nothing was created."));return}await ot("Composing project...","Project composed.",()=>$e(o,n,l,c),s),r.install&&(await ot(`Installing dependencies with ${p}...`,"Dependencies installed.",()=>le(o,p),s),await ot("Formatting...","Formatted.",()=>jt(o,p,"lint:fix"),s)),n.copyEnv&&w(At.join(o,".env.example"))&&await Qi(At.join(o,".env.example"),At.join(o,".env")),r.git&&await ot("Initializing git...","Git initialized.",()=>Rt(o,n.gitRemote,n.pushToRemote),s),a(),m(""),m(I.green(`\u2728 ${n.projectName} is ready.`)),m(""),m("Next:"),m(I.cyan(` cd ${n.projectName}`)),r.install||m(I.cyan(` ${p} install`)),m(I.cyan(` ${p==="pnpm"||p==="yarn"?`${p} dev`:`${p} run dev`}`)),m("")}catch(c){throw a(),s.current?.fail("Failed to create project."),s.current=null,await i(),c}};import Fr from"node:path";import X from"picocolors";import It from"node:path";var Ln=/^[A-Za-z][A-Za-z0-9-]*$/,sa=/^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i;function Un(e){return sa.test(e)}function M(e,t="name"){let r=e?.trim();if(!r)throw new Error(`A ${t} is required.`);if(!Ln.test(r))throw new Error(`Invalid ${t} "${e}". Use letters, digits, and hyphens only \u2014 no slashes, spaces, "..", or absolute paths.`);if(Un(r))throw new Error(`Invalid ${t} "${e}". That is a reserved name on Windows.`);return r}function W(e,t="path"){let r=e?.trim();if(!r)throw new Error(`A ${t} is required.`);let n=r.replace(/^\.\//,"");if(n.startsWith("/")||/^[a-zA-Z]:/.test(n))throw new Error(`Invalid ${t} "${e}". Must be a relative path inside the project (no leading "/" or drive letter).`);for(let o of n.split("/")){if(!Ln.test(o))throw new Error(`Invalid ${t} "${e}". Each segment must be kebab/camel-case (letters, digits, hyphens), separated by "/" \u2014 no "..", dots, or empty segments.`);if(Un(o))throw new Error(`Invalid ${t} "${e}". Segment "${o}" is reserved on Windows.`)}return n}function ne(e,...t){let r=It.resolve(e),n=It.resolve(r,...t),o=It.relative(r,n);if(o===""||o===".")return n;if(o.startsWith("..")||It.isAbsolute(o))throw new Error(`Refusing to write outside the project directory (resolved path escapes "${r}").`);return n}import{execFile as ia}from"node:child_process";import{stat as aa}from"node:fs/promises";import cr from"node:path";import{promisify as ca}from"node:util";var pa=ca(ia),la=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".json",".jsonc",".css"]),ma=e=>cr.join(e,"node_modules",".bin","biome"),pr=async(e,t,r=e)=>{let n=ma(r);if(t.length===0||!w(n))return!1;try{await pa(n,["check","--write","--no-errors-on-unmatched",...t],{cwd:e,maxBuffer:64*1024*1024})}catch(o){if(o.code==="ENOENT")return!1}return!0},k=async(e,t)=>{let r=[];for(let n of await L(e))if(la.has(cr.extname(n)))try{(await aa(cr.join(e,n))).mtimeMs>=t-1e3&&r.push(n)}catch{}return r.length&&await pr(e,r),r};import{access as ua}from"node:fs/promises";import da from"node:path";var ke=async(e,t,r)=>{try{return await ua(da.join(e,r,t)),!0}catch{return!1}};import{access as fa,readFile as Bn}from"node:fs/promises";import lr from"node:path";var Le=async e=>{try{return await fa(e),!0}catch{return!1}},Gn=async e=>{try{return JSON.parse(await Bn(e,"utf-8"))}catch{return null}},O=async e=>{let t=await Gn(lr.join(e,"package.json"));if(!t)throw new Error(`Failed to detect project setup: no package.json in ${e}`);let r={...t.dependencies,...t.devDependencies},n=await Gn(lr.join(e,_e)),o=(...y)=>lr.join(e,...y),s=await Le(o("src","store")),i=!!(r["@reduxjs/toolkit"]&&r["react-redux"])&&s,a=!!r.zustand&&s&&!i,c=i?"redux":a?"zustand":"none",l=await Le(o("src","lib","http","core","client.ts")),p=!!r.axios&&await Le(o("src","lib","http","adapters","axios.ts")),u="none";if(l)if(!p)u="fetch";else{let y="";try{y=await Bn(o("src","lib","http","client.ts"),"utf-8")}catch{}u=y.includes("axiosAdapter")?"axios":"both"}let f=!!r["next-intl"]&&await Le(o("src","i18n")),d=!!r.vitest||await Le(o("vitest.config.ts")),g=r["socket.io-client"]&&await Le(o("src","lib","ws"))?"present":"none";return{state:c,hasRedux:i,httpClient:u,hasI18n:f,hasTests:d,ws:g,hasQuery:!!r["@tanstack/react-query"],hasActions:!!r["next-safe-action"],record:n??void 0}};import{mkdir as ga,writeFile as ha}from"node:fs/promises";import mr from"node:path";var Vn=({pascalName:e,camelName:t})=>`import { z } from 'zod';
57
57
 
58
58
  /**
59
59
  * Wire contracts for the ${t} feature. Types are inferred from the
@@ -78,7 +78,7 @@ export const update${e}InputSchema = create${e}InputSchema.partial().extend({
78
78
  id: z.string(),
79
79
  });
80
80
  export type Update${e}Input = z.infer<typeof update${e}InputSchema>;
81
- `,Mn=({kebabName:e,camelName:t})=>`/**
81
+ `,Hn=({kebabName:e,camelName:t})=>`/**
82
82
  * Query keys owned by the feature. Everything under \`${t}Keys.all\` can
83
83
  * be invalidated at once; narrower keys target one resource.
84
84
  */
@@ -87,7 +87,7 @@ export const ${t}Keys = {
87
87
  list: () => [...${t}Keys.all, 'list'] as const,
88
88
  detail: (id: string) => [...${t}Keys.all, 'detail', id] as const,
89
89
  } as const;
90
- `,_n=({pascalName:e,camelName:t})=>`import 'server-only';
90
+ `,qn=({pascalName:e,camelName:t})=>`import 'server-only';
91
91
 
92
92
  import { AppApis } from '@/lib/config/app-apis';
93
93
  import { serverHttp } from '@/lib/http/server';
@@ -109,7 +109,7 @@ export const list${e}s = async () =>
109
109
 
110
110
  export const get${e} = async (id: string) =>
111
111
  serverHttp.get(AppApis.${t}.detail(id), { schema: ${t}Schema });
112
- `,Dn=({pascalName:e,camelName:t})=>`'use server';
112
+ `,Jn=({pascalName:e,camelName:t})=>`'use server';
113
113
 
114
114
  import { revalidateTag } from 'next/cache';
115
115
 
@@ -158,7 +158,7 @@ export const delete${e} = authActionClient
158
158
  revalidateTag(${t.toUpperCase()}_TAG, 'max');
159
159
  return { deleted: true as const };
160
160
  });
161
- `,Ln=({pascalName:e,camelName:t})=>`import { queryOptions, useSuspenseQuery } from '@tanstack/react-query';
161
+ `,zn=({pascalName:e,camelName:t})=>`import { queryOptions, useSuspenseQuery } from '@tanstack/react-query';
162
162
 
163
163
  import { AppApis } from '@/lib/config/app-apis';
164
164
  import { http } from '@/lib/http';
@@ -187,26 +187,26 @@ export const ${t}Query = (id: string) =>
187
187
 
188
188
  export const use${e}List = () => useSuspenseQuery(${t}ListQuery());
189
189
  export const use${e} = (id: string) => useSuspenseQuery(${t}Query(id));
190
- `,Un=({camelName:e,kebabName:t})=>` ${e}: {
190
+ `,Wn=({camelName:e,kebabName:t})=>` ${e}: {
191
191
  list: '/${t}',
192
192
  detail: (id: string) => \`/${t}/\${id}\`,
193
193
  create: '/${t}',
194
194
  update: (id: string) => \`/${t}/\${id}\`,
195
195
  delete: (id: string) => \`/${t}/\${id}\`,
196
- },`;var nt=async e=>{let{name:t,featurePath:r,withActions:n}=e,o={kebabName:t,camelName:U(t),pascalName:$(t)},s=sr.join(r,"api");await Yi(s,{recursive:!0});let i=[["schema.ts",Fn(o)],["keys.ts",Mn(o)],["server.ts",_n(o)],["queries.ts",Ln(o)]];return n&&i.push(["actions.ts",Dn(o)]),await Promise.all(i.map(([a,p])=>Qi(sr.join(s,a),p))),i.map(([a])=>sr.join("api",a))};import{mkdir as Bn,writeFile as ar}from"node:fs/promises";import $e from"node:path";var ir=e=>{let{componentName:t,isClient:r,hasI18n:n}=e,o=e.translationNamespace||t,s=[];return(r||n)&&s.push("'use client';"),n&&s.push("import { useTranslations } from 'next-intl';"),s.push(""),s.push(`export function ${t}() {`),n?(s.push(` const t = useTranslations('${o}');`),s.push(""),s.push(" return ("),s.push(" <div>"),s.push(" <h2>{t('title')}</h2>"),s.push(" </div>"),s.push(" );")):(s.push(" return ("),s.push(" <div>"),s.push(` <h2>${t}</h2>`),s.push(" </div>"),s.push(" );")),s.push("}"),s.push(""),s.join(`
197
- `)},Gn=e=>`export { ${e.componentName} } from './${e.componentName}';
198
- `;var cr=async e=>{let{name:t,projectPath:r,isClient:n,hasI18n:o,featurePath:s}=e,i=$(t);s?await Zi(i,r,s,n,o):await ea(i,t,r,n,o)},Zi=async(e,t,r,n,o)=>{let s=$e.join(t,r,"components");await Bn(s,{recursive:!0}),await ar($e.join(s,`${e}.tsx`),ir({componentName:e,isClient:n,hasI18n:o}))},ea=async(e,t,r,n,o)=>{let s=$e.join(r,"src","components","common",e);await Bn(s,{recursive:!0}),await ar($e.join(s,`${e}.tsx`),ir({componentName:e,isClient:n,hasI18n:o})),await ar($e.join(s,"index.ts"),Gn({componentName:e}));let i=$e.join(r,"src","components","common","index.ts");await ta(i,`export { ${e} } from './${e}';
199
- `);let a=$e.join(r,"src","components","index.ts");await ra(a)},ta=async(e,t)=>{let r="";y(e)&&(r=await j(e)),r.includes(t.trim())||(r+=t,await k(e,r))},ra=async e=>{let t="";y(e)&&(t=await j(e));let r=`export * from './common';
200
- `;t.includes(r.trim())||(t+=r,await k(e,t))};import{mkdir as mr,writeFile as De}from"node:fs/promises";import H from"node:path";import{mkdir as na,writeFile as Pe}from"node:fs/promises";import ke from"node:path";var lr=e=>{let{sliceName:t,withPersist:r,state:n="redux"}=e;return n==="zustand"?`export * from './${t}.store';
196
+ },`;var st=async e=>{let{name:t,featurePath:r,withActions:n}=e,o={kebabName:t,camelName:G(t),pascalName:$(t)},s=mr.join(r,"api");await ga(s,{recursive:!0});let i=[["schema.ts",Vn(o)],["keys.ts",Hn(o)],["server.ts",qn(o)],["queries.ts",zn(o)]];return n&&i.push(["actions.ts",Jn(o)]),await Promise.all(i.map(([a,c])=>ha(mr.join(s,a),c))),i.map(([a])=>mr.join("api",a))};import{mkdir as Xn,writeFile as dr}from"node:fs/promises";import Pe from"node:path";var ur=e=>{let{componentName:t,isClient:r,hasI18n:n}=e,o=e.translationNamespace||t,s=[];return(r||n)&&s.push("'use client';"),n&&s.push("import { useTranslations } from 'next-intl';"),s.push(""),s.push(`export function ${t}() {`),n?(s.push(` const t = useTranslations('${o}');`),s.push(""),s.push(" return ("),s.push(" <div>"),s.push(" <h2>{t('title')}</h2>"),s.push(" </div>"),s.push(" );")):(s.push(" return ("),s.push(" <div>"),s.push(` <h2>${t}</h2>`),s.push(" </div>"),s.push(" );")),s.push("}"),s.push(""),s.join(`
197
+ `)},Kn=e=>`export { ${e.componentName} } from './${e.componentName}';
198
+ `;var fr=async e=>{let{name:t,projectPath:r,isClient:n,hasI18n:o,featurePath:s}=e,i=$(t);s?await ya(i,r,s,n,o):await wa(i,t,r,n,o)},ya=async(e,t,r,n,o)=>{let s=Pe.join(t,r,"components");await Xn(s,{recursive:!0}),await dr(Pe.join(s,`${e}.tsx`),ur({componentName:e,isClient:n,hasI18n:o}))},wa=async(e,t,r,n,o)=>{let s=Pe.join(r,"src","components","common",e);await Xn(s,{recursive:!0}),await dr(Pe.join(s,`${e}.tsx`),ur({componentName:e,isClient:n,hasI18n:o})),await dr(Pe.join(s,"index.ts"),Kn({componentName:e}));let i=Pe.join(r,"src","components","common","index.ts");await xa(i,`export { ${e} } from './${e}';
199
+ `);let a=Pe.join(r,"src","components","index.ts");await ba(a)},xa=async(e,t)=>{let r="";w(e)&&(r=await j(e)),r.includes(t.trim())||(r+=t,await P(e,r))},ba=async e=>{let t="";w(e)&&(t=await j(e));let r=`export * from './common';
200
+ `;t.includes(r.trim())||(t+=r,await P(e,t))};import{mkdir as yr,writeFile as Ue}from"node:fs/promises";import K from"node:path";import{mkdir as va,writeFile as Se}from"node:fs/promises";import Ee from"node:path";var hr=e=>{let{sliceName:t,withPersist:r,state:n="redux"}=e;return n==="zustand"?`export * from './${t}.store';
201
201
  `:`export * from './${t}.selectors';
202
202
  export * from './${t}.slice';${r?`
203
203
  export * from './persist';`:""}
204
- `},Vn=e=>{let{featureName:t,componentName:r,hookName:n,pascalName:o,withStore:s,withApi:i}=e,a=["/**"," * Client-safe public surface. Server-only pieces live in `./server`."," */"];return i&&(a.push(`export { create${o}, delete${o}, update${o} } from './api/actions';`),a.push(`export { ${pr(t)}Keys } from './api/keys';`),a.push(`export { ${pr(t)}ListQuery, ${pr(t)}Query, use${o}, use${o}List } from './api/queries';`),a.push("export * from './api/schema';")),a.push(`export { ${r} } from './components/${r}';`),i||a.push(`export { ${n} } from './hooks/${n}';`),a.push(`export * from './types/${t}.types';`),s&&a.push("export * from './store';"),`${a.join(`
204
+ `},Yn=e=>{let{featureName:t,componentName:r,hookName:n,pascalName:o,withStore:s,withApi:i}=e,a=["/**"," * Client-safe public surface. Server-only pieces live in `./server`."," */"];return i&&(a.push(`export { create${o}, delete${o}, update${o} } from './api/actions';`),a.push(`export { ${gr(t)}Keys } from './api/keys';`),a.push(`export { ${gr(t)}ListQuery, ${gr(t)}Query, use${o}, use${o}List } from './api/queries';`),a.push("export * from './api/schema';")),a.push(`export { ${r} } from './components/${r}';`),i||a.push(`export { ${n} } from './hooks/${n}';`),a.push(`export * from './types/${t}.types';`),s&&a.push("export * from './store';"),`${a.join(`
205
205
  `)}
206
- `},qn=e=>`import 'server-only';
206
+ `},Qn=e=>`import 'server-only';
207
207
 
208
208
  export { get${e.pascalName}, list${e.pascalName}s, ${e.pascalName.toUpperCase()}_TAG } from './api/server';
209
- `,pr=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase());var Jn=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e,o=`${r.replace(/[A-Z]/g,s=>`_${s}`).toUpperCase()}_PERSIST_VERSION`;return`import { definePersistence } from '@/store/persistence';
209
+ `,gr=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase());var Zn=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e,o=`${r.replace(/[A-Z]/g,s=>`_${s}`).toUpperCase()}_PERSIST_VERSION`;return`import { definePersistence } from '@/store/persistence';
210
210
 
211
211
  import type { ${t}State } from '${n}';
212
212
 
@@ -224,12 +224,12 @@ export const ${r}Persistence = definePersistence<${t}State>({
224
224
  // 2: (previous) => ({ ...(previous as ${t}State), newField: 0 }),
225
225
  },
226
226
  });
227
- `};var zn=e=>{let{componentName:t,camelName:r}=e;return`import type { RootState } from '@/store/rootReducer';
227
+ `};var eo=e=>{let{componentName:t,camelName:r}=e;return`import type { RootState } from '@/store/rootReducer';
228
228
 
229
229
  export const select${t}State = (state: RootState) => state.${r};
230
230
  export const select${t}Status = (state: RootState) => state.${r}.status;
231
231
  export const select${t}Error = (state: RootState) => state.${r}.error;
232
- `};var Wn=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e;return`import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
232
+ `};var to=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e;return`import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
233
233
 
234
234
  import type { ${t}State } from '${n}';
235
235
 
@@ -256,7 +256,7 @@ export const ${r}Slice = createSlice({
256
256
 
257
257
  export const { started, failed, reset } = ${r}Slice.actions;
258
258
  export const ${r}Reducer = ${r}Slice.reducer;
259
- `};var Ot=e=>{let{componentName:t,withStore:r}=e;return r?`export type ${t}Status = 'idle' | 'loading' | 'error';
259
+ `};var Nt=e=>{let{componentName:t,withStore:r}=e;return r?`export type ${t}Status = 'idle' | 'loading' | 'error';
260
260
 
261
261
  export interface ${t}State {
262
262
  status: ${t}Status;
@@ -265,7 +265,7 @@ export interface ${t}State {
265
265
  `:`export interface ${t}Props {
266
266
  // Props for the ${t} component
267
267
  }
268
- `};var Hn=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e;return`import type { StateCreator } from 'zustand';
268
+ `};var ro=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e;return`import type { StateCreator } from 'zustand';
269
269
 
270
270
  import type { ${t}State } from '${n}';
271
271
 
@@ -292,15 +292,15 @@ export const create${t}Slice: StateCreator<any, [], [], ${t}Slice> = (set) => ({
292
292
  ${r}Failed: (error: string) => set({ ${r}: { status: 'error', error } }),
293
293
  ${r}Reset: () => set({ ${r}: initial }),
294
294
  });
295
- `};var ot=async e=>{let{name:t,outputPath:r,persist:n,state:o="redux",typesImportPath:s=`./${t}.types`}=e;await na(r,{recursive:!0});let i=$(t),a=U(t),p=[];s===`./${t}.types`&&p.push(Pe(ke.join(r,`${t}.types.ts`),Ot({componentName:i,withStore:!0}))),o==="zustand"?p.push(Pe(ke.join(r,`${t}.store.ts`),Hn({componentName:i,camelName:a,typesImportPath:s})),Pe(ke.join(r,"index.ts"),lr({sliceName:t,withPersist:!1,state:o}))):(p.push(Pe(ke.join(r,`${t}.slice.ts`),Wn({componentName:i,camelName:a,typesImportPath:s})),Pe(ke.join(r,`${t}.selectors.ts`),zn({componentName:i,camelName:a,sliceName:t})),Pe(ke.join(r,"index.ts"),lr({sliceName:t,withPersist:n,state:o}))),n&&p.push(Pe(ke.join(r,"persist.ts"),Jn({componentName:i,camelName:a,typesImportPath:s})))),await Promise.all(p)};var Kn=e=>{let{componentName:t,hookName:r,withApi:n,pascalName:o,hasI18n:s}=e,i=s?`import { useTranslations } from 'next-intl';
295
+ `};var it=async e=>{let{name:t,outputPath:r,persist:n,state:o="redux",typesImportPath:s=`./${t}.types`}=e;await va(r,{recursive:!0});let i=$(t),a=G(t),c=[];s===`./${t}.types`&&c.push(Se(Ee.join(r,`${t}.types.ts`),Nt({componentName:i,withStore:!0}))),o==="zustand"?c.push(Se(Ee.join(r,`${t}.store.ts`),ro({componentName:i,camelName:a,typesImportPath:s})),Se(Ee.join(r,"index.ts"),hr({sliceName:t,withPersist:!1,state:o}))):(c.push(Se(Ee.join(r,`${t}.slice.ts`),to({componentName:i,camelName:a,typesImportPath:s})),Se(Ee.join(r,`${t}.selectors.ts`),eo({componentName:i,camelName:a,sliceName:t})),Se(Ee.join(r,"index.ts"),hr({sliceName:t,withPersist:n,state:o}))),n&&c.push(Se(Ee.join(r,"persist.ts"),Zn({componentName:i,camelName:a,typesImportPath:s})))),await Promise.all(c)};var no=e=>{let{componentName:t,hookName:r,withApi:n,pascalName:o,hasI18n:s}=e,i=s?`import { useTranslations } from 'next-intl';
296
296
 
297
297
  `:"",a=s?` const t = useTranslations('${o}');
298
- `:"",p=s?"{t('title')}":t;return n?`'use client';
298
+ `:"",c=s?"{t('title')}":t;return n?`'use client';
299
299
 
300
300
  ${i}import { use${o}List } from '../api/queries';
301
301
 
302
302
  /**
303
- * Renders hydrated query data: prefetch \`${oa(o)}ListQuery()\` in the
303
+ * Renders hydrated query data: prefetch \`${$a(o)}ListQuery()\` in the
304
304
  * page and wrap this component in \`<HydrateQueries>\` for a no-spinner first paint.
305
305
  */
306
306
  export function ${t}() {
@@ -308,7 +308,7 @@ ${a} const { data } = use${o}List();
308
308
 
309
309
  return (
310
310
  <section className="flex flex-col gap-2">
311
- <h2 className="font-medium text-sm">${p}</h2>
311
+ <h2 className="font-medium text-sm">${c}</h2>
312
312
  <ul className="flex flex-col gap-1">
313
313
  {data.map((item) => (
314
314
  <li key={item.id}>{item.title}</li>
@@ -326,21 +326,21 @@ ${a} const state = ${r}();
326
326
 
327
327
  return (
328
328
  <section className="flex flex-col gap-2">
329
- <h2 className="font-medium text-sm">${p}</h2>
329
+ <h2 className="font-medium text-sm">${c}</h2>
330
330
  <pre className="text-xs">{JSON.stringify(state, null, 2)}</pre>
331
331
  </section>
332
332
  );
333
333
  }
334
- `},oa=e=>e.charAt(0).toLowerCase()+e.slice(1);var Xn=e=>{let{hookName:t,componentName:r,featureName:n,state:o}=e;return o==="zustand"?`'use client';
334
+ `},$a=e=>e.charAt(0).toLowerCase()+e.slice(1);var oo=e=>{let{hookName:t,componentName:r,featureName:n,state:o}=e;return o==="zustand"?`'use client';
335
335
 
336
336
  import { useAppStore } from '@/store/hooks';
337
337
 
338
338
  export const ${t} = () => {
339
- const status = useAppStore((state) => state.${st(n)}.status);
340
- const error = useAppStore((state) => state.${st(n)}.error);
341
- const start = useAppStore((state) => state.${st(n)}Started);
342
- const fail = useAppStore((state) => state.${st(n)}Failed);
343
- const reset = useAppStore((state) => state.${st(n)}Reset);
339
+ const status = useAppStore((state) => state.${at(n)}.status);
340
+ const error = useAppStore((state) => state.${at(n)}.error);
341
+ const start = useAppStore((state) => state.${at(n)}Started);
342
+ const fail = useAppStore((state) => state.${at(n)}Failed);
343
+ const reset = useAppStore((state) => state.${at(n)}Reset);
344
344
 
345
345
  return { status, error, start, fail, reset } as const;
346
346
  };
@@ -364,7 +364,7 @@ export const ${t} = () => {
364
364
  reset: () => dispatch(reset()),
365
365
  } as const;
366
366
  };
367
- `},st=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),At=e=>{let{hookName:t}=e;return`'use client';
367
+ `},at=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),Ft=e=>{let{hookName:t}=e;return`'use client';
368
368
 
369
369
  import { useCallback, useState } from 'react';
370
370
 
@@ -382,7 +382,7 @@ export const ${t} = () => {
382
382
 
383
383
  return { busy, run } as const;
384
384
  };
385
- `};var It=e=>{let{componentName:t,sourceImportPath:r,testUtilsImportPath:n,hasState:o,hasI18n:s,withQueryData:i}=e,a=[];if(s&&a.push("messages: {}"),o&&a.push("preloadedState: {}"),i)return`import { describe, expect, it } from 'vitest';
385
+ `};var Mt=e=>{let{componentName:t,sourceImportPath:r,testUtilsImportPath:n,hasState:o,hasI18n:s,withQueryData:i}=e,a=[];if(s&&a.push("messages: {}"),o&&a.push("preloadedState: {}"),i)return`import { describe, expect, it } from 'vitest';
386
386
 
387
387
  import { makeTestQueryClient, renderWithProviders, screen } from '${n}';
388
388
  import { ${i.keys} } from '${i.keysImport}';
@@ -398,18 +398,18 @@ describe('${t}', () => {
398
398
  expect(screen.getByText('First')).toBeInTheDocument();
399
399
  });
400
400
  });
401
- `;let p=a.length?`, { ${a.join(", ")} }`:"";return`import { describe, expect, it } from 'vitest';
401
+ `;let c=a.length?`, { ${a.join(", ")} }`:"";return`import { describe, expect, it } from 'vitest';
402
402
 
403
403
  import { renderWithProviders, screen } from '${n}';
404
404
  import { ${t} } from '${r}';
405
405
 
406
406
  describe('${t}', () => {
407
407
  it('renders', () => {
408
- renderWithProviders(<${t} />${p});
408
+ renderWithProviders(<${t} />${c});
409
409
  expect(screen.getByRole('heading')).toBeInTheDocument();
410
410
  });
411
411
  });
412
- `},Yn=e=>{let{hookName:t,sourceImportPath:r,withStore:n,testUtilsImportPath:o}=e;return n?`// @vitest-environment jsdom
412
+ `},so=e=>{let{hookName:t,sourceImportPath:r,withStore:n,testUtilsImportPath:o}=e;return n?`// @vitest-environment jsdom
413
413
  import { renderHook } from '@testing-library/react';
414
414
  import { describe, expect, it } from 'vitest';
415
415
 
@@ -434,7 +434,7 @@ describe('${t}', () => {
434
434
  expect(result.current).toBeDefined();
435
435
  });
436
436
  });
437
- `},Qn=e=>{let{camelName:t,sourceImportPath:r}=e,n=`${t}Slice`;return`import { describe, expect, it } from 'vitest';
437
+ `},io=e=>{let{camelName:t,sourceImportPath:r}=e,n=`${t}Slice`;return`import { describe, expect, it } from 'vitest';
438
438
 
439
439
  import { failed, reset, ${n}, started } from '${r}';
440
440
 
@@ -456,7 +456,7 @@ describe('${n}', () => {
456
456
  expect(${n}.reducer({ status: 'error', error: 'boom' }, reset())).toEqual(initialState);
457
457
  });
458
458
  });
459
- `};var dr=async e=>{let{name:t,outputPath:r,createStore:n,persistStore:o,createApi:s,state:i,hasI18n:a,hasTests:p}=e,m=$(t),c=s?`${m}List`:m,d=`use${m}`,u=n&&i!=="none";await mr(H.join(r,"components"),{recursive:!0}),await mr(H.join(r,"types"),{recursive:!0}),s||await mr(H.join(r,"hooks"),{recursive:!0});let f=[De(H.join(r,"components",`${c}.tsx`),Kn({componentName:c,hookName:d,withApi:s,pascalName:m,hasI18n:a})),De(H.join(r,"types",`${t}.types.ts`),Ot({componentName:m,withStore:u})),De(H.join(r,"index.ts"),Vn({featureName:t,componentName:c,hookName:d,pascalName:m,withStore:u,withApi:s}))];s||f.push(De(H.join(r,"hooks",`${d}.ts`),u?Xn({hookName:d,componentName:m,featureName:t,state:i==="zustand"?"zustand":"redux"}):At({hookName:d}))),s&&(f.push(nt({name:t,featurePath:r,withActions:!0})),f.push(De(H.join(r,"server.ts"),qn({pascalName:m})))),p&&f.push(De(H.join(r,"components",`${c}.test.tsx`),It({componentName:c,sourceImportPath:`./${c}`,testUtilsImportPath:"../../../../test/test-utils",hasState:i!=="none",hasI18n:a,withQueryData:s?{keysImport:"../api/keys",keys:`${sa(t)}Keys`,key:"list"}:void 0}))),await Promise.all(f),u&&await ot({name:t,outputPath:H.join(r,"store"),persist:o,state:i==="zustand"?"zustand":"redux",typesImportPath:`../types/${t}.types`})},sa=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase());import{mkdir as ia,writeFile as aa}from"node:fs/promises";import ur from"node:path";var fr=async e=>{let{name:t,projectPath:r,featurePath:n}=e,o=`use${$(t)}`,s=n?ur.join(r,n,"hooks"):ur.join(r,"src","hooks");await ia(s,{recursive:!0}),await aa(ur.join(s,`${o}.ts`),At({hookName:o}))};import{mkdir as ca}from"node:fs/promises";import Nt from"node:path";var Zn=({componentName:e})=>`type Props = {
459
+ `};var wr=async e=>{let{name:t,outputPath:r,createStore:n,persistStore:o,createApi:s,state:i,hasI18n:a,hasTests:c}=e,l=$(t),p=s?`${l}List`:l,u=`use${l}`,f=n&&i!=="none";await yr(K.join(r,"components"),{recursive:!0}),await yr(K.join(r,"types"),{recursive:!0}),s||await yr(K.join(r,"hooks"),{recursive:!0});let d=[Ue(K.join(r,"components",`${p}.tsx`),no({componentName:p,hookName:u,withApi:s,pascalName:l,hasI18n:a})),Ue(K.join(r,"types",`${t}.types.ts`),Nt({componentName:l,withStore:f})),Ue(K.join(r,"index.ts"),Yn({featureName:t,componentName:p,hookName:u,pascalName:l,withStore:f,withApi:s}))];s||d.push(Ue(K.join(r,"hooks",`${u}.ts`),f?oo({hookName:u,componentName:l,featureName:t,state:i==="zustand"?"zustand":"redux"}):Ft({hookName:u}))),s&&(d.push(st({name:t,featurePath:r,withActions:!0})),d.push(Ue(K.join(r,"server.ts"),Qn({pascalName:l})))),c&&d.push(Ue(K.join(r,"components",`${p}.test.tsx`),Mt({componentName:p,sourceImportPath:`./${p}`,testUtilsImportPath:"../../../../test/test-utils",hasState:i!=="none",hasI18n:a,withQueryData:s?{keysImport:"../api/keys",keys:`${ka(t)}Keys`,key:"list"}:void 0}))),await Promise.all(d),f&&await it({name:t,outputPath:K.join(r,"store"),persist:o,state:i==="zustand"?"zustand":"redux",typesImportPath:`../types/${t}.types`})},ka=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase());import{mkdir as Pa,writeFile as Sa}from"node:fs/promises";import xr from"node:path";var br=async e=>{let{name:t,projectPath:r,featurePath:n}=e,o=`use${$(t)}`,s=n?xr.join(r,n,"hooks"):xr.join(r,"src","hooks");await Pa(s,{recursive:!0}),await Sa(xr.join(s,`${o}.ts`),Ft({hookName:o}))};import{mkdir as Ea}from"node:fs/promises";import _t from"node:path";var ao=({componentName:e})=>`type Props = {
460
460
  children: React.ReactNode;
461
461
  };
462
462
 
@@ -465,15 +465,15 @@ describe('${n}', () => {
465
465
  export default function ${e}({ children }: Props) {
466
466
  return <>{children}</>;
467
467
  }
468
- `;var pa=/^[a-z][a-z0-9-]*$/,la=/^[a-z][a-z0-9-]*(\/[a-z][a-z0-9-]*)*$/,ma=e=>{if(!pa.test(e))throw new Error(`Invalid layout segment "${e}". Use kebab-case letters, digits, and hyphens. For route groups pass --group instead of wrapping in parens.`)},da=e=>{if(!la.test(e))throw new Error(`Invalid --at path "${e}". Use kebab-case segments separated by "/", e.g. "dashboard/settings".`)},gr=async e=>{let{segment:t,at:r,projectPath:n,hasI18n:o,withGroup:s}=e;ma(t),r&&da(r);let i=`${$(t)}Layout`,a=s?`(${t})`:t,p=["src","app"];o&&p.push("[locale]"),r&&p.push(...r.split("/")),p.push(a);let m=Nt.join(n,...p),c=Nt.join(m,"layout.tsx");if(y(c))throw new Error(`Layout already exists at ${Nt.relative(n,c)}.`);return await ca(m,{recursive:!0}),await k(c,Zn({componentName:i,hasI18n:o})),{layoutFile:c,displayPath:Nt.relative(n,c),componentName:i}};import{copyFile as ua,readFile as fa,writeFile as ga}from"node:fs/promises";import it from"node:path";var hr=async e=>{let{code:t,name:r,country:n,flag:o,projectPath:s,copyTranslations:i}=e;await ha(s,t,i),await ya(s,t),await wa(s,t,r,n,o)},ha=async(e,t,r)=>{let n=it.join(e,"src","i18n","translations"),o=it.join(n,"en.json"),s=it.join(n,`${t}.json`);if(r)await ua(o,s);else{let i=await fa(o,"utf-8"),a=JSON.parse(i),p=eo(a);await ga(s,`${JSON.stringify(p,null,2)}
469
- `)}},eo=e=>{let t={};for(let[r,n]of Object.entries(e))typeof n=="object"&&n!==null?t[r]=eo(n):t[r]="";return t},ya=async(e,t)=>{let r=it.join(e,"src","types","i18n.ts");if(!y(r))return;let n=await j(r),o=/export const SUPPORTED_LOCALES = \[([^\]]*)\] as const;/,s=n.match(o);if(s){if(s[1].includes(`'${t}'`))return;let p=s[1].split(",").map(m=>m.trim()).filter(Boolean);p.push(`'${t}'`),n=n.replace(o,`export const SUPPORTED_LOCALES = [${p.join(", ")}] as const;`),await k(r,n);return}let i=/export type SupportedLocale = (.*);/,a=n.match(i);a&&!a[1].includes(`'${t}'`)&&(n=n.replace(i,`export type SupportedLocale = ${a[1]} | '${t}';`),await k(r,n))},wa=async(e,t,r,n,o)=>{let s=it.join(e,"src","lib","config","app-locales.ts");if(!y(s))return;let i=await j(s);if(i.includes(`locale: '${t}'`))return;let a=i.lastIndexOf("];");if(a===-1)return;let p=` {
468
+ `;var Ta=/^[a-z][a-z0-9-]*$/,Ra=/^[a-z][a-z0-9-]*(\/[a-z][a-z0-9-]*)*$/,ja=e=>{if(!Ta.test(e))throw new Error(`Invalid layout segment "${e}". Use kebab-case letters, digits, and hyphens. For route groups pass --group instead of wrapping in parens.`)},Ca=e=>{if(!Ra.test(e))throw new Error(`Invalid --at path "${e}". Use kebab-case segments separated by "/", e.g. "dashboard/settings".`)},vr=async e=>{let{segment:t,at:r,projectPath:n,hasI18n:o,withGroup:s}=e;ja(t),r&&Ca(r);let i=`${$(t)}Layout`,a=s?`(${t})`:t,c=["src","app"];o&&c.push("[locale]"),r&&c.push(...r.split("/")),c.push(a);let l=_t.join(n,...c),p=_t.join(l,"layout.tsx");if(w(p))throw new Error(`Layout already exists at ${_t.relative(n,p)}.`);return await Ea(l,{recursive:!0}),await P(p,ao({componentName:i,hasI18n:o})),{layoutFile:p,displayPath:_t.relative(n,p),componentName:i}};import{copyFile as Oa,readFile as Aa,writeFile as Ia}from"node:fs/promises";import ct from"node:path";var $r=async e=>{let{code:t,name:r,country:n,flag:o,projectPath:s,copyTranslations:i}=e;await Na(s,t,i),await Fa(s,t),await Ma(s,t,r,n,o)},Na=async(e,t,r)=>{let n=ct.join(e,"src","i18n","translations"),o=ct.join(n,"en.json"),s=ct.join(n,`${t}.json`);if(r)await Oa(o,s);else{let i=await Aa(o,"utf-8"),a=JSON.parse(i),c=co(a);await Ia(s,`${JSON.stringify(c,null,2)}
469
+ `)}},co=e=>{let t={};for(let[r,n]of Object.entries(e))typeof n=="object"&&n!==null?t[r]=co(n):t[r]="";return t},Fa=async(e,t)=>{let r=ct.join(e,"src","types","i18n.ts");if(!w(r))return;let n=await j(r),o=/export const SUPPORTED_LOCALES = \[([^\]]*)\] as const;/,s=n.match(o);if(s){if(s[1].includes(`'${t}'`))return;let c=s[1].split(",").map(l=>l.trim()).filter(Boolean);c.push(`'${t}'`),n=n.replace(o,`export const SUPPORTED_LOCALES = [${c.join(", ")}] as const;`),await P(r,n);return}let i=/export type SupportedLocale = (.*);/,a=n.match(i);a&&!a[1].includes(`'${t}'`)&&(n=n.replace(i,`export type SupportedLocale = ${a[1]} | '${t}';`),await P(r,n))},Ma=async(e,t,r,n,o)=>{let s=ct.join(e,"src","lib","config","app-locales.ts");if(!w(s))return;let i=await j(s);if(i.includes(`locale: '${t}'`))return;let a=i.lastIndexOf("];");if(a===-1)return;let c=` {
470
470
  name: '${r}',
471
471
  locale: '${t}',
472
472
  flag: '${o}',
473
473
  country: '${n}',
474
474
  ogLocale: '${t}_${t.toUpperCase()}',
475
475
  },
476
- `;i=i.slice(0,a)+p+i.slice(a),await k(s,i)};import{mkdir as ba,writeFile as yr}from"node:fs/promises";import Ft from"node:path";var xa=({routePath:e,hasI18n:t,paramName:r})=>`${t?"/[locale]":""}${e}${r?`/[${r}]`:""}`,to=e=>{let{componentName:t,routePath:r,hasI18n:n,paramName:o}=e,s=xa(e);return n?`import type { Metadata } from 'next';
476
+ `;i=i.slice(0,a)+c+i.slice(a),await P(s,i)};import{mkdir as Da,writeFile as kr}from"node:fs/promises";import Dt from"node:path";var _a=({routePath:e,hasI18n:t,paramName:r})=>`${t?"/[locale]":""}${e}${r?`/[${r}]`:""}`,po=e=>{let{componentName:t,routePath:r,hasI18n:n,paramName:o}=e,s=_a(e);return n?`import type { Metadata } from 'next';
477
477
  import { getLocale, getTranslations } from 'next-intl/server';
478
478
 
479
479
  import { generateSEOMetadata } from '@/lib/config/seo';
@@ -520,14 +520,14 @@ ${o?` const { ${o} } = await params;
520
520
  </div>
521
521
  );
522
522
  }
523
- `},ro=e=>`export default function ${e.componentName}Loading() {
523
+ `},lo=e=>`export default function ${e.componentName}Loading() {
524
524
  return (
525
525
  <div className="flex h-full items-center justify-center p-6">
526
526
  <p className="text-gray-500 text-sm dark:text-gray-400">Loading\u2026</p>
527
527
  </div>
528
528
  );
529
529
  }
530
- `,no=e=>`'use client';
530
+ `,mo=e=>`'use client';
531
531
 
532
532
  import { useEffect } from 'react';
533
533
 
@@ -557,7 +557,7 @@ export default function ${e.componentName}Error({
557
557
  </div>
558
558
  );
559
559
  }
560
- `;var wr=async e=>{let{name:t,projectPath:r,hasI18n:n,group:o,dynamic:s,withLoading:i=!1,withError:a=!1}=e,p=$(t),m=`/${t}`,c=[r,"src","app"];n&&c.push("[locale]"),o&&c.push(`(${o})`),c.push(t),s&&c.push(`[${s}]`);let d=Ft.join(...c);return await ba(d,{recursive:!0}),await yr(Ft.join(d,"page.tsx"),to({componentName:p,routePath:m,hasI18n:n,paramName:s})),i&&await yr(Ft.join(d,"loading.tsx"),ro({componentName:p})),a&&await yr(Ft.join(d,"error.tsx"),no({componentName:p})),{pageDir:d,routePath:s?`${m}/[${s}]`:m}};import{mkdir as va}from"node:fs/promises";import xr from"node:path";var oo=(e,t)=>e.endsWith(t)?e:`${e}${t}`,so=({baseName:e})=>{let t=oo(e,"Provider"),r=t.replace(/Provider$/,""),n=`${r}ContextValue`,o=`${r}Context`,s=`use${r}`;return`'use client';
560
+ `;var Pr=async e=>{let{name:t,projectPath:r,hasI18n:n,group:o,dynamic:s,withLoading:i=!1,withError:a=!1}=e,c=$(t),l=`/${t}`,p=[r,"src","app"];n&&p.push("[locale]"),o&&p.push(`(${o})`),p.push(t),s&&p.push(`[${s}]`);let u=Dt.join(...p);return await Da(u,{recursive:!0}),await kr(Dt.join(u,"page.tsx"),po({componentName:c,routePath:l,hasI18n:n,paramName:s})),i&&await kr(Dt.join(u,"loading.tsx"),lo({componentName:c})),a&&await kr(Dt.join(u,"error.tsx"),mo({componentName:c})),{pageDir:u,routePath:s?`${l}/[${s}]`:l}};import{mkdir as La}from"node:fs/promises";import Sr from"node:path";var uo=(e,t)=>e.endsWith(t)?e:`${e}${t}`,fo=({baseName:e})=>{let t=uo(e,"Provider"),r=t.replace(/Provider$/,""),n=`${r}ContextValue`,o=`${r}Context`,s=`use${r}`;return`'use client';
561
561
  import { createContext, useContext, useMemo } from 'react';
562
562
 
563
563
  type ${n} = {
@@ -578,130 +578,139 @@ export const ${t} = ({ children }: { children: React.ReactNode }) => {
578
578
  const value = useMemo<${n}>(() => ({}), []);
579
579
  return <${o}.Provider value={value}>{children}</${o}.Provider>;
580
580
  };
581
- `},io=e=>oo(e,"Provider");var $a=/^[A-Za-z][A-Za-z0-9-]*$/,Pa=e=>e.includes("-")?$(e):e.charAt(0).toUpperCase()+e.slice(1),br=async e=>{let{name:t,projectPath:r}=e;if(!$a.test(t))throw new Error(`Invalid provider name "${t}". Use kebab-case or PascalCase letters and digits only.`);let n=Pa(t).replace(/Provider$/,""),o=io(n),s=o,i=xr.join(r,C.PROVIDERS),a=xr.join(i,`${s}.tsx`);if(y(a))throw new Error(`Provider already exists at ${xr.relative(r,a)}.`);return await va(i,{recursive:!0}),await k(a,so({baseName:n})),{componentName:o,fileBaseName:s,providerFile:a}};import at from"node:path";var re=async e=>{let{projectPath:t,sourceFile:r,kind:n,symbolName:o}=e,s=at.dirname(r),i=at.basename(r).replace(/\.(tsx?|jsx?)$/i,""),a=n==="component"?".tsx":".ts",p=at.join(s,`${i}.test${a}`),m=`./${i}`,c=ka(s,at.join(t,"test","test-utils")),d;return n==="component"?d=It({componentName:o,sourceImportPath:m,testUtilsImportPath:c,hasState:!!e.hasState,hasI18n:!!e.hasI18n}):n==="hook"?d=Yn({hookName:o,sourceImportPath:m,withStore:!!e.hookUsesStore,testUtilsImportPath:e.hookUsesStore?c:void 0}):d=Qn({camelName:o,sourceImportPath:m}),await k(p,d),p},ka=(e,t)=>{let r=at.relative(e,t).replace(/\\/g,"/");return r.startsWith(".")?r:`./${r}`};import{readFile as Sa,writeFile as Ea}from"node:fs/promises";import Ra from"node:path";var Le=(e,t)=>{let r=/import\s+.*\s+from\s+['"].*['"];?\n/g,n=e.match(r);if(n&&n.length>0){let o=n[n.length-1],s=e.lastIndexOf(o);return e.slice(0,s+o.length)+t+`
581
+ `},go=e=>uo(e,"Provider");var Ua=/^[A-Za-z][A-Za-z0-9-]*$/,Ga=e=>e.includes("-")?$(e):e.charAt(0).toUpperCase()+e.slice(1),Er=async e=>{let{name:t,projectPath:r}=e;if(!Ua.test(t))throw new Error(`Invalid provider name "${t}". Use kebab-case or PascalCase letters and digits only.`);let n=Ga(t).replace(/Provider$/,""),o=go(n),s=o,i=Sr.join(r,C.PROVIDERS),a=Sr.join(i,`${s}.tsx`);if(w(a))throw new Error(`Provider already exists at ${Sr.relative(r,a)}.`);return await La(i,{recursive:!0}),await P(a,fo({baseName:n})),{componentName:o,fileBaseName:s,providerFile:a}};import pt from"node:path";var oe=async e=>{let{projectPath:t,sourceFile:r,kind:n,symbolName:o}=e,s=pt.dirname(r),i=pt.basename(r).replace(/\.(tsx?|jsx?)$/i,""),a=n==="component"?".tsx":".ts",c=pt.join(s,`${i}.test${a}`),l=`./${i}`,p=Ba(s,pt.join(t,"test","test-utils")),u;return n==="component"?u=Mt({componentName:o,sourceImportPath:l,testUtilsImportPath:p,hasState:!!e.hasState,hasI18n:!!e.hasI18n}):n==="hook"?u=so({hookName:o,sourceImportPath:l,withStore:!!e.hookUsesStore,testUtilsImportPath:e.hookUsesStore?p:void 0}):u=io({camelName:o,sourceImportPath:l}),await P(c,u),c},Ba=(e,t)=>{let r=pt.relative(e,t).replace(/\\/g,"/");return r.startsWith(".")?r:`./${r}`};import{readFile as Va,writeFile as Ha}from"node:fs/promises";import qa from"node:path";var Ge=(e,t)=>{let r=/import\s+.*\s+from\s+['"].*['"];?\n/g,n=e.match(r);if(n&&n.length>0){let o=n[n.length-1],s=e.lastIndexOf(o);return e.slice(0,s+o.length)+t+`
582
582
  `+e.slice(s+o.length)}return`${t}
583
- ${e}`},vr=(e,t)=>{let r=/combineSlices\(([\s\S]*?)\)/,n=e.match(r);if(!n)throw new Error("Could not find combineSlices in rootReducer.ts");let o=n[1].split(",").map(p=>p.trim()).filter(Boolean);if(o.includes(t))return e;let s=o.indexOf("persistSlice");s===-1?o.push(t):o.splice(s,0,t);let i=`combineSlices(${o.join(", ")})`,a=`combineSlices(
583
+ ${e}`},Tr=(e,t)=>{let r=/combineSlices\(([\s\S]*?)\)/,n=e.match(r);if(!n)throw new Error("Could not find combineSlices in rootReducer.ts");let o=n[1].split(",").map(c=>c.trim()).filter(Boolean);if(o.includes(t))return e;let s=o.indexOf("persistSlice");s===-1?o.push(t):o.splice(s,0,t);let i=`combineSlices(${o.join(", ")})`,a=`combineSlices(
584
584
  ${o.join(`,
585
585
  `)},
586
- )`;return e.replace(r,i.length<=100?i:a)},$r=(e,t)=>{let r=/entries:\s*\[([\s\S]*?)\]/,n=e.match(r);if(!n)throw new Error("Could not find `entries: [...]` in src/store/index.ts");let o=n[1].split(",").map(s=>s.trim()).filter(Boolean);return o.includes(t)?e:(o.push(t),e.replace(r,`entries: [${o.join(", ")}]`))},Pr=(e,t)=>{let r=e.lastIndexOf("} as const;");if(r===-1)throw new Error("Could not find closing brace of AppApis object");let n=e.substring(0,r),o=e.substring(r);return`${n.trimEnd()}
586
+ )`;return e.replace(r,i.length<=100?i:a)},Rr=(e,t)=>{let r=/entries:\s*\[([\s\S]*?)\]/,n=e.match(r);if(!n)throw new Error("Could not find `entries: [...]` in src/store/index.ts");let o=n[1].split(",").map(s=>s.trim()).filter(Boolean);return o.includes(t)?e:(o.push(t),e.replace(r,`entries: [${o.join(", ")}]`))},jr=(e,t)=>{let r=e.lastIndexOf("} as const;");if(r===-1)throw new Error("Could not find closing brace of AppApis object");let n=e.substring(0,r),o=e.substring(r);return`${n.trimEnd()}
587
587
  ${t}
588
- ${o}`};var ct=async e=>{let{serviceName:t,projectPath:r}=e,n=U(t),o=Ra.join(r,"src","lib","config","app-apis.ts");try{let s=await Sa(o,"utf-8");if(s.includes(`${n}:`))return;if(!s.match(/export const AppApis = \{[\s\S]*?\} as const;/))throw new Error("Could not find AppApis object in app-apis.ts");s=Pr(s,Un({kebabName:t,camelName:n,pascalName:$(t)})),await Ea(o,s)}catch(s){throw new Error(`Failed to register API endpoints: ${s}`,{cause:s})}};import{readFile as ja,writeFile as Ca}from"node:fs/promises";import Ta from"node:path";var kr=async(e,t,r)=>{let n=Ta.join(e,"src","lib","config","app-paths.ts");if(!y(n))return;let o=await ja(n,"utf-8"),s=U(t);if(o.includes(`${s}:`))return;let i=o.lastIndexOf("} as const;");if(i===-1)return;let a=` ${s}: '${r}',
589
- `;o=o.slice(0,i)+a+o.slice(i),await Ca(n,o)};import Sr from"node:path";var Oa=/^[A-Z][A-Z0-9_]*$/,po=e=>{if(!Oa.test(e))throw new Error(`Invalid env var name "${e}". Use UPPER_SNAKE_CASE (e.g. SENTRY_DSN, NEXT_PUBLIC_API_URL).`)},ne=(e,t)=>t?e.startsWith("NEXT_PUBLIC_")?e:`NEXT_PUBLIC_${e}`:e,Er=e=>e.public?"client":"server",Aa=e=>{if(e.default===void 0)return"";switch(e.type){case"number":return`.default(${Number(e.default)})`;case"boolean":return`.default(${e.default==="true"})`;default:return`.default('${e.default.replace(/'/g,"\\'")}')`}},Ia=e=>{switch(e.type){case"url":return"e.url()";case"number":return"e.number()";case"boolean":return"e.boolean()";case"enum":{let t=e.enumValues??[];if(t.length===0)throw new Error(`Enum env var "${e.name}" requires --enum values.`);return`e.enum([${t.map(n=>`'${n.replace(/'/g,"\\'")}'`).join(", ")}])`}default:return"e.string()"}},lo=e=>{let t=ne(e.name,e.public),r=Ia(e),n=e.default!==void 0,o=!e.required&&!n;if(n&&(r+=Aa(e)),o&&(r+=".optional()"),e.description){let s=e.description.replace(/'/g,"\\'");r+=`
590
- .describe('${s}')`}return` ${t}: ${r},`},mo=e=>{let t=ne(e.name,e.public);return` ${t}: process.env.${t},`},Na=e=>new RegExp(`(${e}:\\s*\\{)([\\s\\S]*?)(\\n\\s*\\})`),ao=/(runtimeEnv:\s*\{)([\s\S]*?)(\n\s*\})/,co=(e,t,r,n)=>{let o=t.replace(/\s+$/,""),s=o.length===0||/,\s*$/.test(o)?o:`${o},`;return`${e}${s}
588
+ ${o}`};var lt=async e=>{let{serviceName:t,projectPath:r}=e,n=G(t),o=qa.join(r,"src","lib","config","app-apis.ts");try{let s=await Va(o,"utf-8");if(s.includes(`${n}:`))return;if(!s.match(/export const AppApis = \{[\s\S]*?\} as const;/))throw new Error("Could not find AppApis object in app-apis.ts");s=jr(s,Wn({kebabName:t,camelName:n,pascalName:$(t)})),await Ha(o,s)}catch(s){throw new Error(`Failed to register API endpoints: ${s}`,{cause:s})}};import{readFile as Ja,writeFile as za}from"node:fs/promises";import Wa from"node:path";var Cr=async(e,t,r)=>{let n=Wa.join(e,"src","lib","config","app-paths.ts");if(!w(n))return;let o=await Ja(n,"utf-8"),s=G(t);if(o.includes(`${s}:`))return;let i=o.lastIndexOf("} as const;");if(i===-1)return;let a=` ${s}: '${r}',
589
+ `;o=o.slice(0,i)+a+o.slice(i),await za(n,o)};import Or from"node:path";var Ka=/^[A-Z][A-Z0-9_]*$/,wo=e=>{if(!Ka.test(e))throw new Error(`Invalid env var name "${e}". Use UPPER_SNAKE_CASE (e.g. SENTRY_DSN, NEXT_PUBLIC_API_URL).`)},se=(e,t)=>t?e.startsWith("NEXT_PUBLIC_")?e:`NEXT_PUBLIC_${e}`:e,Ar=e=>e.public?"client":"server",Xa=e=>{if(e.default===void 0)return"";switch(e.type){case"number":return`.default(${Number(e.default)})`;case"boolean":return`.default(${e.default==="true"})`;default:return`.default('${e.default.replace(/'/g,"\\'")}')`}},Ya=e=>{switch(e.type){case"url":return"e.url()";case"number":return"e.number()";case"boolean":return"e.boolean()";case"enum":{let t=e.enumValues??[];if(t.length===0)throw new Error(`Enum env var "${e.name}" requires --enum values.`);return`e.enum([${t.map(n=>`'${n.replace(/'/g,"\\'")}'`).join(", ")}])`}default:return"e.string()"}},xo=e=>{let t=se(e.name,e.public),r=Ya(e),n=e.default!==void 0,o=!e.required&&!n;if(n&&(r+=Xa(e)),o&&(r+=".optional()"),e.description){let s=e.description.replace(/'/g,"\\'");r+=`
590
+ .describe('${s}')`}return` ${t}: ${r},`},bo=e=>{let t=se(e.name,e.public);return` ${t}: process.env.${t},`},Qa=e=>new RegExp(`(${e}:\\s*\\{)([\\s\\S]*?)(\\n\\s*\\})`),ho=/(runtimeEnv:\s*\{)([\s\S]*?)(\n\s*\})/,yo=(e,t,r,n)=>{let o=t.replace(/\s+$/,""),s=o.length===0||/,\s*$/.test(o)?o:`${o},`;return`${e}${s}
591
591
  ${n}
592
- ${r.replace(/^\n/,"")}`},uo=(e,t)=>{let r=ne(t.name,t.public),n=Er(t);if(new RegExp(`\\b${r}\\s*:`).test(e))return e;if(!/defineEnv\(\{/.test(e))throw new Error("Could not locate `defineEnv({ \u2026 })` in src/lib/env/index.ts. Is this a @teispace/env project?");let s=Na(n),i=e.match(s);if(!i)throw new Error(`Could not locate the \`${n}: { \u2026 }\` group in src/lib/env/index.ts.`);let[,a,p,m]=i,c=lo(t),d=e.replace(s,co(a,p,m,c)),u=d.match(ao);if(!u)throw new Error("Could not locate the `runtimeEnv: { \u2026 }` map in src/lib/env/index.ts.");let[,f,h,w]=u;return d=d.replace(ao,co(f,h,w,mo(t))),d},Fa="# -public",Ma=e=>{let t=ne(e.name,e.public),r=e.default??"",n=e.public?` ${Fa}`:"";return`${t}=${r}${n}`},fo=(e,t)=>{let r=ne(t.name,t.public);if(new RegExp(`^${r}=`,"m").test(e))return e;let o=e===""||e.endsWith(`
592
+ ${r.replace(/^\n/,"")}`},vo=(e,t)=>{let r=se(t.name,t.public),n=Ar(t);if(new RegExp(`\\b${r}\\s*:`).test(e))return e;if(!/defineEnv\(\{/.test(e))throw new Error("Could not locate `defineEnv({ \u2026 })` in src/lib/env/index.ts. Is this a @teispace/env project?");let s=Qa(n),i=e.match(s);if(!i)throw new Error(`Could not locate the \`${n}: { \u2026 }\` group in src/lib/env/index.ts.`);let[,a,c,l]=i,p=xo(t),u=e.replace(s,yo(a,c,l,p)),f=u.match(ho);if(!f)throw new Error("Could not locate the `runtimeEnv: { \u2026 }` map in src/lib/env/index.ts.");let[,d,g,y]=f;return u=u.replace(ho,yo(d,g,y,bo(t))),u},Za="# -public",ec=e=>{let t=se(e.name,e.public),r=e.default??"",n=e.public?` ${Za}`:"";return`${t}=${r}${n}`},$o=(e,t)=>{let r=se(t.name,t.public);if(new RegExp(`^${r}=`,"m").test(e))return e;let o=e===""||e.endsWith(`
593
593
  `)?"":`
594
594
  `,s=e===""?"":`
595
595
  `,i=t.description?`# ${t.description}
596
- `:"";return`${e}${o}${s}${i}${Ma(t)}
597
- `},go=(e,t)=>{let r=ne(t.name,t.public);if(new RegExp(`^${r}=`,"m").test(e))return e;let o=e===""||e.endsWith(`
596
+ `:"";return`${e}${o}${s}${i}${ec(t)}
597
+ `},ko=(e,t)=>{let r=se(t.name,t.public);if(new RegExp(`^${r}=`,"m").test(e))return e;let o=e===""||e.endsWith(`
598
598
  `)?"":`
599
599
  `,s=t.default??"";return`${e}${o}${r}=${s}
600
- `},Rr=async(e,t)=>{po(t.name);let r=Sr.join(e,"src/lib/env/index.ts");if(!y(r))throw new Error("src/lib/env/index.ts not found \u2014 run `next-maker init` first.");let n=await j(r),o=uo(n,t),s=o!==n;s&&await k(r,o);let i=Sr.join(e,C.ENV_EXAMPLE),a=!1;if(y(i)){let c=await j(i),d=fo(c,t);a=d!==c,a&&await k(i,d)}let p=Sr.join(e,".env"),m=!1;if(y(p)){let c=await j(p),d=go(c,t);m=d!==c,m&&await k(p,d)}return{schemaUpdated:s,envExampleUpdated:a,envUpdated:m,group:Er(t)}};import Mt from"node:path";var _a=e=>new RegExp(`<\\s*${e}\\b`),ho=(e,t)=>{if(_a(t).test(e))return e;let r=/^(?<indent>[ \t]*)\{children\}\s*$/m,n=e.match(r);if(!n||n.index===void 0)throw new Error("Could not locate `{children}` line in RootProvider \u2014 expected a line containing only `{children}`.");let o=n.groups?.indent??"",s=`${o} `,i=`${o}<${t}>
600
+ `},Ir=async(e,t)=>{wo(t.name);let r=Or.join(e,"src/lib/env/index.ts");if(!w(r))throw new Error("src/lib/env/index.ts not found \u2014 run `next-maker init` first.");let n=await j(r),o=vo(n,t),s=o!==n;s&&await P(r,o);let i=Or.join(e,C.ENV_EXAMPLE),a=!1;if(w(i)){let p=await j(i),u=$o(p,t);a=u!==p,a&&await P(i,u)}let c=Or.join(e,".env"),l=!1;if(w(c)){let p=await j(c),u=ko(p,t);l=u!==p,l&&await P(c,u)}return{schemaUpdated:s,envExampleUpdated:a,envUpdated:l,group:Ar(t)}};import Lt from"node:path";var tc=e=>new RegExp(`<\\s*${e}\\b`),Po=(e,t)=>{if(tc(t).test(e))return e;let r=/^(?<indent>[ \t]*)\{children\}\s*$/m,n=e.match(r);if(!n||n.index===void 0)throw new Error("Could not locate `{children}` line in RootProvider \u2014 expected a line containing only `{children}`.");let o=n.groups?.indent??"",s=`${o} `,i=`${o}<${t}>
601
601
  ${s}{children}
602
- ${o}</${t}>`;return e.replace(r,i)},yo=(e,t)=>{let r=`export * from './${t}';`;if(e.includes(r))return e;let n=e.split(`
603
- `),o=[],s=[];for(let d of n)/^export \* from '\.\/.*';\s*$/.test(d)?o.push(d):s.push(d);let i=[...o,r].sort(),a=n.findIndex(d=>/^export \* from '\.\//.test(d));if(a===-1)return`${r}
604
- ${e.replace(/^\n+/,"")}`;let p=n.slice(0,a),m=n.findIndex((d,u)=>u>a&&!/^export \* from '\.\//.test(d)),c=m===-1?[]:n.slice(m);return[...p,...i,...c].join(`
605
- `)},Da=C.PROVIDERS,La=C.ROOT_PROVIDER,Ua=C.PROVIDERS_INDEX,wo=async(e,t={fileExists:y,readFile:j})=>{let r=Mt.join(e,La);if(t.fileExists(r))return r;let n=Mt.join(e,Da);if(!t.fileExists(n))return null;let{readdir:o}=await import("node:fs/promises"),i=(await o(n).catch(()=>[])).filter(p=>p.endsWith(".tsx")),a=null;for(let p of i){let m=Mt.join(n,p),c=await t.readFile(m);if(!/\{children\}/.test(c))continue;let u=((c.split("{children}")[0]??"").match(/<[A-Z][A-Za-z0-9_]*\b/g)??[]).length;(!a||u>a.depth)&&(a={file:m,depth:u})}return a?.file??null},jr=async e=>{let{projectPath:t,componentName:r,fileBaseName:n}=e,o=await wo(t);if(o){let a=await j(o),p=a;(!/from '\.\//.test(a)||!a.includes(`{ ${r} }`))&&(p=Le(p,`import { ${r} } from './${n}';`)),p=ho(p,r),p!==a&&await k(o,p)}let s=Mt.join(t,Ua),i=null;if(y(s)){let a=await j(s),p=yo(a,n);p!==a&&await k(s,p),i=s}return{rootProviderFile:o,barrelFile:i}};import{readFile as xo,writeFile as bo}from"node:fs/promises";import vo from"node:path";var pt=async e=>{let{projectPath:t,name:r,persist:n,importPath:o}=e,s=vo.join(t,"src","store","rootReducer.ts"),i=vo.join(t,"src","store","index.ts"),a=U(r),p=o.replace(/^src\//,"@/");try{let m=await xo(s,"utf-8");if(m=Le(m,`import { ${a}Slice } from '${p}';`),m=vr(m,`${a}Slice`),await bo(s,m),n&&y(i)){let c=await xo(i,"utf-8");c=Le(c,`import { ${a}Persistence } from '${p}';`),c=$r(c,`${a}Persistence`),await bo(i,c)}}catch(m){throw new Error(`Failed to register slice '${r}': ${m}`,{cause:m})}};import{readFile as Ga,writeFile as Ba}from"node:fs/promises";import Va from"node:path";var Se=async(e,t)=>{let r=Va.join(e,"src","i18n","translations","en.json");if(!y(r))return;let n=await Ga(r,"utf-8"),o=JSON.parse(n);o[t]||(o[t]={title:t,description:`${t} page description`},await Ba(r,`${JSON.stringify(o,null,2)}
606
- `))};import qa from"enquirer";var{prompt:Ja}=qa,$o=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"componentName",message:"Component name (kebab-case):",validate:o=>o?/^[a-z][a-z0-9-]*$/.test(o)?!0:"Use lowercase letters, numbers, and hyphens only":"Component name is required"}),t.client===void 0&&r.push({type:"confirm",name:"isClient",message:"Add 'use client' directive?",initial:!1});let n=r.length>0?await Ja(r):{};return{componentName:e??n.componentName,isClient:t.client??n.isClient??!1}};var Po=e=>{e.command("component [name]").description("Generate a shared component").option("--client","Add 'use client' directive").option("--i18n","Add useTranslations hook").option("--feature <path>","Generate in feature directory (e.g., src/features/auth)").option("--test","Also generate a sibling test file").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd();l(K.cyan(`
602
+ ${o}</${t}>`;return e.replace(r,i)},So=(e,t)=>{let r=`export * from './${t}';`;if(e.includes(r))return e;let n=e.split(`
603
+ `),o=[],s=[];for(let u of n)/^export \* from '\.\/.*';\s*$/.test(u)?o.push(u):s.push(u);let i=[...o,r].sort(),a=n.findIndex(u=>/^export \* from '\.\//.test(u));if(a===-1)return`${r}
604
+ ${e.replace(/^\n+/,"")}`;let c=n.slice(0,a),l=n.findIndex((u,f)=>f>a&&!/^export \* from '\.\//.test(u)),p=l===-1?[]:n.slice(l);return[...c,...i,...p].join(`
605
+ `)},rc=C.PROVIDERS,nc=C.ROOT_PROVIDER,oc=C.PROVIDERS_INDEX,Eo=async(e,t={fileExists:w,readFile:j})=>{let r=Lt.join(e,nc);if(t.fileExists(r))return r;let n=Lt.join(e,rc);if(!t.fileExists(n))return null;let{readdir:o}=await import("node:fs/promises"),i=(await o(n).catch(()=>[])).filter(c=>c.endsWith(".tsx")),a=null;for(let c of i){let l=Lt.join(n,c),p=await t.readFile(l);if(!/\{children\}/.test(p))continue;let f=((p.split("{children}")[0]??"").match(/<[A-Z][A-Za-z0-9_]*\b/g)??[]).length;(!a||f>a.depth)&&(a={file:l,depth:f})}return a?.file??null},Nr=async e=>{let{projectPath:t,componentName:r,fileBaseName:n}=e,o=await Eo(t);if(o){let a=await j(o),c=a;(!/from '\.\//.test(a)||!a.includes(`{ ${r} }`))&&(c=Ge(c,`import { ${r} } from './${n}';`)),c=Po(c,r),c!==a&&await P(o,c)}let s=Lt.join(t,oc),i=null;if(w(s)){let a=await j(s),c=So(a,n);c!==a&&await P(s,c),i=s}return{rootProviderFile:o,barrelFile:i}};import{readFile as To,writeFile as Ro}from"node:fs/promises";import jo from"node:path";var mt=async e=>{let{projectPath:t,name:r,persist:n,importPath:o}=e,s=jo.join(t,"src","store","rootReducer.ts"),i=jo.join(t,"src","store","index.ts"),a=G(r),c=o.replace(/^src\//,"@/");try{let l=await To(s,"utf-8");if(l=Ge(l,`import { ${a}Slice } from '${c}';`),l=Tr(l,`${a}Slice`),await Ro(s,l),n&&w(i)){let p=await To(i,"utf-8");p=Ge(p,`import { ${a}Persistence } from '${c}';`),p=Rr(p,`${a}Persistence`),await Ro(i,p)}}catch(l){throw new Error(`Failed to register slice '${r}': ${l}`,{cause:l})}};import{readFile as sc,writeFile as ic}from"node:fs/promises";import ac from"node:path";var Te=async(e,t)=>{let r=ac.join(e,"src","i18n","translations","en.json");if(!w(r))return;let n=await sc(r,"utf-8"),o=JSON.parse(n);o[t]||(o[t]={title:t,description:`${t} page description`},await ic(r,`${JSON.stringify(o,null,2)}
606
+ `))};import cc from"enquirer";var{prompt:pc}=cc,Co=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"componentName",message:"Component name (kebab-case):",validate:o=>o?/^[a-z][a-z0-9-]*$/.test(o)?!0:"Use lowercase letters, numbers, and hyphens only":"Component name is required"}),t.client===void 0&&r.push({type:"confirm",name:"isClient",message:"Add 'use client' directive?",initial:!1});let n=r.length>0?await pc(r):{};return{componentName:e??n.componentName,isClient:t.client??n.isClient??!1}};var Oo=e=>{e.command("component [name]").description("Generate a shared component").option("--client","Add 'use client' directive").option("--i18n","Add useTranslations hook").option("--feature <path>","Generate in feature directory (e.g., src/features/auth)").option("--test","Also generate a sibling test file").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(X.cyan(`
607
607
  \u{1F9E9} Component Generator
608
- `)),g.start("Detecting project setup...");let o=await T(n);g.succeed("Project setup detected");let s=await $o(t,{client:r.client});F(s.componentName,"component name"),r.feature&&W(r.feature,"feature path");let i=$(s.componentName),a=s.isClient,p=r.i18n??!1,m=za(r,o.hasTests);g.start("Generating component..."),await cr({name:s.componentName,projectPath:n,isClient:a||p,hasI18n:p,featurePath:r.feature}),g.succeed("Component generated"),p&&await Se(n,i);let c=null;if(m){let u=r.feature?Cr.join(n,r.feature,"components",`${i}.tsx`):Cr.join(n,"src/components/common",i,`${i}.tsx`);g.start("Generating test..."),c=await re({projectPath:n,sourceFile:u,kind:"component",symbolName:i,hasState:o.state!=="none",hasI18n:o.hasI18n}),g.succeed("Test generated")}let d=r.feature?`${r.feature}/components/${i}.tsx`:`src/components/common/${i}/${i}.tsx`;l(K.green(`
609
- \u2728 Component '${i}' created successfully!
610
- `)),l(K.dim(` \u{1F4C4} ${d}`)),r.feature||(l(K.dim(` \u{1F4C4} src/components/common/${i}/index.ts`)),l(K.dim(" \u{1F4DD} Updated src/components/common/index.ts")),l(K.dim(" \u{1F4DD} Updated src/components/index.ts"))),c&&l(K.dim(` \u{1F9EA} ${Cr.relative(n,c)}`)),l(""),l(K.cyan("Usage:")),r.feature?l(K.dim(` import { ${i} } from '${r.feature.replace(/^src\//,"@/")}/components/${i}';`)):l(K.dim(` import { ${i} } from '@/components';`)),l("")}catch(n){g.fail("Component generation failed"),x(`${n}`),process.exit(1)}})},za=(e,t)=>e.test===!1?!1:e.test===!0?!0:t;import{spawnSync as Wa}from"node:child_process";import M from"picocolors";var Ha=e=>{switch(e.kind){case"missingFile":return`missing file: ${e.file}`;case"missingPackage":return`missing ${e.dev?"devDependency":"dependency"}: ${e.name}`;case"missingScript":return`missing script: ${e.name}`}},ko=e=>{e.command("doctor").description("Diagnose drift between the project and the starter features it was generated with").option("--fix","Restore missing files, packages, and scripts from the starter").option("--compile","Run the project type-check as part of the diagnosis").option("--json","Print machine-readable JSON").option("--starter-path <dir>","Compare against a local starter checkout").action(async t=>{let r=process.cwd(),n;try{let o=await ee(r),s=await Me(o,{starterPath:t.starterPath});n=s.dispose;let i=await rr(r,o,s),a=0;if(t.fix&&i.some(c=>c.drift.length)){let c=await Sn(r,{...o,answers:{}},s,o.answers),d=new Set(i.flatMap(h=>h.drift.filter(w=>w.kind==="missingFile").map(w=>w.file)));c.copy=c.copy.filter(h=>d.has(h)),c.remove=[],c.unwrapJsx=[],c.unwrapCall=[],c.removePackages=[],c.removeScripts=[],c.manual=[];let u=new Set(i.flatMap(h=>h.drift.filter(w=>w.kind==="missingPackage").map(w=>w.name)));for(let h of Object.keys(c.addPackages))u.has(h)||delete c.addPackages[h];for(let h of Object.keys(c.addDevPackages))u.has(h)||delete c.addDevPackages[h];let f=new Set(i.flatMap(h=>h.drift.filter(w=>w.kind==="missingScript").map(w=>w.name)));for(let h of Object.keys(c.addScripts))f.has(h)||delete c.addScripts[h];await En(r,s,c,o),a=c.copy.length+Object.keys(c.addPackages).length+Object.keys(c.addDevPackages).length+Object.keys(c.addScripts).length,i=await rr(r,o,s)}let p;if(t.compile){let[c,...d]=ae(o.packageManager,"type-check").split(" "),u=Wa(c,d,{cwd:r,encoding:"utf-8"});p={ok:u.status===0,output:`${u.stdout}${u.stderr}`.trim()}}let m=i.filter(c=>c.on&&c.drift.length);t.json&&(l(JSON.stringify({starter:o.starter,results:i,fixed:a,compile:p},null,2)),process.exit(m.length||p?.ok===!1?1:0)),l(M.cyan(`
608
+ `)),h.start("Detecting project setup...");let s=await O(n);h.succeed("Project setup detected");let i=await Co(t,{client:r.client});M(i.componentName,"component name"),r.feature&&W(r.feature,"feature path");let a=$(i.componentName),c=i.isClient,l=r.i18n??!1,p=lc(r,s.hasTests);h.start("Generating component..."),await fr({name:i.componentName,projectPath:n,isClient:c||l,hasI18n:l,featurePath:r.feature}),h.succeed("Component generated"),l&&await Te(n,a);let u=null;if(p){let d=r.feature?Fr.join(n,r.feature,"components",`${a}.tsx`):Fr.join(n,"src/components/common",a,`${a}.tsx`);h.start("Generating test..."),u=await oe({projectPath:n,sourceFile:d,kind:"component",symbolName:a,hasState:s.state!=="none",hasI18n:s.hasI18n}),h.succeed("Test generated")}let f=r.feature?`${r.feature}/components/${a}.tsx`:`src/components/common/${a}/${a}.tsx`;await k(n,o),m(X.green(`
609
+ \u2728 Component '${a}' created successfully!
610
+ `)),m(X.dim(` \u{1F4C4} ${f}`)),r.feature||(m(X.dim(` \u{1F4C4} src/components/common/${a}/index.ts`)),m(X.dim(" \u{1F4DD} Updated src/components/common/index.ts")),m(X.dim(" \u{1F4DD} Updated src/components/index.ts"))),u&&m(X.dim(` \u{1F9EA} ${Fr.relative(n,u)}`)),m(""),m(X.cyan("Usage:")),r.feature?m(X.dim(` import { ${a} } from '${r.feature.replace(/^src\//,"@/")}/components/${a}';`)):m(X.dim(` import { ${a} } from '@/components';`)),m("")}catch(n){h.fail("Component generation failed"),b(`${n}`),process.exit(1)}})},lc=(e,t)=>e.test===!1?!1:e.test===!0?!0:t;import{spawnSync as mc}from"node:child_process";import _ from"picocolors";var uc=e=>{switch(e.kind){case"missingFile":return`missing file: ${e.file}`;case"missingPackage":return`missing ${e.dev?"devDependency":"dependency"}: ${e.name}`;case"missingScript":return`missing script: ${e.name}`}},Ao=e=>{e.command("doctor").description("Diagnose drift between the project and the starter features it was generated with").option("--fix","Restore missing files, packages, and scripts from the starter").option("--compile","Run the project type-check as part of the diagnosis").option("--json","Print machine-readable JSON").option("--starter-path <dir>","Compare against a local starter checkout").action(async t=>{let r=process.cwd(),n;try{let o=await re(r),s=await De(o,{starterPath:t.starterPath});n=s.dispose;let i=await ir(r,o,s),a=0;if(t.fix&&i.some(p=>p.drift.length)){let p=await In(r,{...o,answers:{}},s,o.answers),u=new Set(i.flatMap(g=>g.drift.filter(y=>y.kind==="missingFile").map(y=>y.file)));p.copy=p.copy.filter(g=>u.has(g)),p.remove=[],p.unwrapJsx=[],p.unwrapCall=[],p.removePackages=[],p.removeScripts=[],p.manual=[];let f=new Set(i.flatMap(g=>g.drift.filter(y=>y.kind==="missingPackage").map(y=>y.name)));for(let g of Object.keys(p.addPackages))f.has(g)||delete p.addPackages[g];for(let g of Object.keys(p.addDevPackages))f.has(g)||delete p.addDevPackages[g];let d=new Set(i.flatMap(g=>g.drift.filter(y=>y.kind==="missingScript").map(y=>y.name)));for(let g of Object.keys(p.addScripts))d.has(g)||delete p.addScripts[g];await Nn(r,s,p,o),a=p.copy.length+Object.keys(p.addPackages).length+Object.keys(p.addDevPackages).length+Object.keys(p.addScripts).length,i=await ir(r,o,s)}let c;if(t.compile){let[p,...u]=ce(o.packageManager,"type-check").split(" "),f=mc(p,u,{cwd:r,encoding:"utf-8"});c={ok:f.status===0,output:`${f.stdout}${f.stderr}`.trim()}}let l=i.filter(p=>p.on&&p.drift.length);t.json&&(m(JSON.stringify({starter:o.starter,results:i,fixed:a,compile:c},null,2)),process.exit(l.length||c?.ok===!1?1:0)),m(_.cyan(`
611
611
  \u{1FA7A} Project Doctor
612
- `)),l(M.dim(` ${o.starter.name} ${o.starter.version} \xB7 ${s.source.location}
613
- `));for(let c of i){if(!c.on){l(` ${M.dim("\u2014")} ${M.dim(c.id)} ${M.dim("(off)")}`);continue}if(c.drift.length===0){l(` ${M.green("\u2713")} ${c.id}`);continue}l(` ${M.yellow("!")} ${M.bold(c.id)} ${M.dim(`(${c.drift.length} issue${c.drift.length===1?"":"s"})`)}`);for(let d of c.drift)l(` ${M.yellow("\u2022")} ${Ha(d)}`)}a&&l(M.green(`
614
- restored ${a} item(s) from the starter`)),p&&(l(""),l(p.ok?M.green(" \u2713 type-check passed"):M.red(" \u2717 type-check failed")),p.ok||l(M.dim(p.output.split(`
612
+ `)),m(_.dim(` ${o.starter.name} ${o.starter.version} \xB7 ${s.source.location}
613
+ `));for(let p of i){if(!p.on){m(` ${_.dim("\u2014")} ${_.dim(p.id)} ${_.dim("(off)")}`);continue}if(p.drift.length===0){m(` ${_.green("\u2713")} ${p.id}`);continue}m(` ${_.yellow("!")} ${_.bold(p.id)} ${_.dim(`(${p.drift.length} issue${p.drift.length===1?"":"s"})`)}`);for(let u of p.drift)m(` ${_.yellow("\u2022")} ${uc(u)}`)}a&&m(_.green(`
614
+ restored ${a} item(s) from the starter`)),c&&(m(""),m(c.ok?_.green(" \u2713 type-check passed"):_.red(" \u2717 type-check failed")),c.ok||m(_.dim(c.output.split(`
615
615
  `).slice(-30).join(`
616
- `)))),l(""),m.length===0&&p?.ok!==!1&&(l(M.green(`\u2713 No drift detected.
617
- `)),process.exit(0)),m.length&&!t.fix&&l(M.dim(`Run with --fix to restore missing pieces from the starter.
618
- `)),process.exit(1)}catch(o){x(`${o instanceof Error?o.message:o}`),process.exit(1)}finally{await n?.()}})};import Ue from"picocolors";var So=new Set(["string","url","number","boolean","enum"]),Ka=e=>{let t=(e??"string").toLowerCase();if(!So.has(t))throw new Error(`Invalid --type "${e}". Valid: ${Array.from(So).join(", ")}.`);return t},Xa=e=>{if(!e)return;let t=e.split(",").map(r=>r.trim()).filter(Boolean);return t.length===0?void 0:t},Eo=e=>{e.command("env <NAME>").description("Declare a new environment variable across src/lib/env/index.ts, .env.example, and .env").option("--type <type>","Coercer type (string|url|number|boolean|enum)","string").option("--required","Make the variable required (no .optional() / .default())").option("--default <value>","Set a default value (mutually exclusive with --required)").option("--public","Mark as public: place in the client group, auto-prefix NEXT_PUBLIC_, tag .env.example").option("--describe <text>","Description (rendered as .describe() and .env.example comment)").option("--enum <list>",'Comma-separated values when --type=enum (e.g. "dev,prod")').action(async(t,r)=>{try{let n=process.cwd();if(l(Ue.cyan(`
616
+ `)))),m(""),l.length===0&&c?.ok!==!1&&(m(_.green(`\u2713 No drift detected.
617
+ `)),process.exit(0)),l.length&&!t.fix&&m(_.dim(`Run with --fix to restore missing pieces from the starter.
618
+ `)),process.exit(1)}catch(o){b(`${o instanceof Error?o.message:o}`),process.exit(1)}finally{await n?.()}})};import Be from"picocolors";var Io=new Set(["string","url","number","boolean","enum"]),dc=e=>{let t=(e??"string").toLowerCase();if(!Io.has(t))throw new Error(`Invalid --type "${e}". Valid: ${Array.from(Io).join(", ")}.`);return t},fc=e=>{if(!e)return;let t=e.split(",").map(r=>r.trim()).filter(Boolean);return t.length===0?void 0:t},No=e=>{e.command("env <NAME>").description("Declare a new environment variable across src/lib/env/index.ts, .env.example, and .env").option("--type <type>","Coercer type (string|url|number|boolean|enum)","string").option("--required","Make the variable required (no .optional() / .default())").option("--default <value>","Set a default value (mutually exclusive with --required)").option("--public","Mark as public: place in the client group, auto-prefix NEXT_PUBLIC_, tag .env.example").option("--describe <text>","Description (rendered as .describe() and .env.example comment)").option("--enum <list>",'Comma-separated values when --type=enum (e.g. "dev,prod")').action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();if(m(Be.cyan(`
619
619
  \u{1F510} Env Var Generator
620
- `)),r.required&&r.default!==void 0)throw new Error("--required and --default are mutually exclusive.");let o=Ka(r.type),s=Xa(r.enum);if(o==="enum"&&(!s||s.length===0))throw new Error("--type=enum requires at least one value via --enum a,b,c.");let i={name:t,type:o,required:!!r.required,default:r.default,description:r.describe,enumValues:s,public:!!r.public};g.start("Updating src/lib/env/index.ts, .env.example, and .env...");let a=await Rr(n,i);g.succeed("Env var written");let p=ne(i.name,i.public);l(Ue.green(`
621
- \u2728 ${p} declared in the ${a.group} group.
622
- `)),l(Ue.dim("Touched:")),l(Ue.dim(` ${a.schemaUpdated?"\u270F\uFE0F ":"\u23ED "} src/lib/env/index.ts`)),l(Ue.dim(` ${a.envExampleUpdated?"\u270F\uFE0F ":"\u23ED "} .env.example`)),l(Ue.dim(` ${a.envUpdated?"\u270F\uFE0F ":"\u23ED "} .env`)),l("")}catch(n){g.fail("Env var declaration failed"),x(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import Lt from"node:path";import Re from"picocolors";import Ya from"enquirer";var{prompt:Qa}=Ya,Ro=async(e={})=>e.source?{source:e.source}:{source:(await Qa({type:"input",name:"source",message:"Path to source image (PNG/JPG/JPEG/SVG/WebP/AVIF):",validate:r=>r?!0:"Source path is required"})).source};import{access as Za,readFile as ec,stat as tc}from"node:fs/promises";import Ee from"node:path";var jo=async e=>{try{return await Za(e),!0}catch{return!1}},rc=async e=>{try{return(await tc(e)).isDirectory()}catch{return!1}},_t=async e=>{let t=[Ee.join(e,"src","app"),Ee.join(e,"app")];for(let r of t)if(await rc(r))return r;return null},nc=["next-pwa","@ducanh2912/next-pwa","@serwist/next","serwist"],Tr=async e=>{let t={isPwa:!1},r=[Ee.join(e,"public","manifest.json"),Ee.join(e,"public","manifest.webmanifest"),Ee.join(e,"public","site.webmanifest")];for(let o of r)if(await jo(o)){t.publicManifestPath=o,t.isPwa=!0;break}let n=await _t(e);if(n)for(let o of["ts","tsx","js"]){let s=Ee.join(n,`manifest.${o}`);if(await jo(s)){t.appManifestPath=s,t.isPwa=!0;break}}try{let o=JSON.parse(await ec(Ee.join(e,"package.json"),"utf-8")),s={...o.dependencies,...o.devDependencies};for(let i of nc)if(s[i]){t.framework=i,t.isPwa=!0;break}}catch{}return t};import{mkdir as cc,readFile as Do,stat as pc,writeFile as lc}from"node:fs/promises";import X from"node:path";import mc from"sharp";import sc from"png-to-ico";import lt from"sharp";var Co=e=>e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;"),Or=(e,t,r)=>{switch(e){case"square":return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><rect width="${t}" height="${t}" fill="white"/></svg>`;case"circle":{let n=t/2;return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><circle cx="${n}" cy="${n}" r="${n}" fill="white"/></svg>`}case"rounded":{let n=Math.round(t*r/100);return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><rect width="${t}" height="${t}" rx="${n}" ry="${n}" fill="white"/></svg>`}case"squircle":return oc(t)}},oc=e=>{let t=e,r=t*.225,n=[`M 0 ${r}`,`C 0 0 0 0 ${r} 0`,`L ${t-r} 0`,`C ${t} 0 ${t} 0 ${t} ${r}`,`L ${t} ${t-r}`,`C ${t} ${t} ${t} ${t} ${t-r} ${t}`,`L ${r} ${t}`,`C 0 ${t} 0 ${t} 0 ${t-r}`,"Z"].join(" ");return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><path d="${Co(n)}" fill="white"/></svg>`},To=(e,t)=>`<svg xmlns="http://www.w3.org/2000/svg" width="${e}" height="${e}"><rect width="${e}" height="${e}" fill="${Co(t)}"/></svg>`;var Ge=async e=>{let{size:t,paddingPercent:r,bg:n,fit:o,shape:s,radiusPercent:i,quality:a,forceSquare:p,sourceBuffer:m}=e,c=Math.max(1,Math.round(t*(1-r*2/100))),d=o==="cover"?"cover":"contain",u=await lt(m,{density:384}).resize(c,c,{fit:d,background:{r:0,g:0,b:0,alpha:0}}).png().toBuffer(),f=Math.round((t-c)/2),h=n==="transparent"?{r:0,g:0,b:0,alpha:0}:await Ar(n),w=await lt({create:{width:t,height:t,channels:4,background:h}}).composite([{input:u,left:f,top:f}]).png().toBuffer();if(!p&&(s!=="square"||o==="clip")){let b=s==="square"?"rounded":s,S=Buffer.from(Or(b,t,i));w=await lt(w).composite([{input:S,blend:"dest-in"}]).png({compressionLevel:Oo(a)}).toBuffer()}else w=await lt(w).png({compressionLevel:Oo(a)}).toBuffer();return w},Ar=async e=>{let t=await lt(Buffer.from(To(1,e))).raw().toBuffer({resolveWithObject:!0}),[r,n,o,s=255]=t.data;return{r,g:n,b:o,alpha:s/255}},Oo=e=>{let t=Math.round((100-e)/100*9);return Math.max(0,Math.min(9,t))},Ao=async e=>{if(e.length===0)throw new Error("No frames provided to encodeIco");return sc(e)};import{readFile as ic,writeFile as xf}from"node:fs/promises";var Io=e=>e.map(({src:t,size:r})=>({src:t,sizes:`${r}x${r}`,type:"image/png",purpose:"any maskable"})),No=async(e,t)=>{let r=await ic(e,"utf-8"),n=JSON.parse(r),o=Array.isArray(n.icons)?n.icons:[],s=new Map;for(let i of[...o,...t])i&&typeof i.src=="string"&&s.set(i.src,i);return n.icons=[...s.values()],`${JSON.stringify(n,null,2)}
623
- `};var Fo=e=>`icons: [
620
+ `)),r.required&&r.default!==void 0)throw new Error("--required and --default are mutually exclusive.");let s=dc(r.type),i=fc(r.enum);if(s==="enum"&&(!i||i.length===0))throw new Error("--type=enum requires at least one value via --enum a,b,c.");let a={name:t,type:s,required:!!r.required,default:r.default,description:r.describe,enumValues:i,public:!!r.public};h.start("Updating src/lib/env/index.ts, .env.example, and .env...");let c=await Ir(n,a);h.succeed("Env var written");let l=se(a.name,a.public);await k(n,o),m(Be.green(`
621
+ \u2728 ${l} declared in the ${c.group} group.
622
+ `)),m(Be.dim("Touched:")),m(Be.dim(` ${c.schemaUpdated?"\u270F\uFE0F ":"\u23ED "} src/lib/env/index.ts`)),m(Be.dim(` ${c.envExampleUpdated?"\u270F\uFE0F ":"\u23ED "} .env.example`)),m(Be.dim(` ${c.envUpdated?"\u270F\uFE0F ":"\u23ED "} .env`)),m("")}catch(n){h.fail("Env var declaration failed"),b(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import Bt from"node:path";import je from"picocolors";import gc from"enquirer";var{prompt:hc}=gc,Fo=async(e={})=>e.source?{source:e.source}:{source:(await hc({type:"input",name:"source",message:"Path to source image (PNG/JPG/JPEG/SVG/WebP/AVIF):",validate:r=>r?!0:"Source path is required"})).source};import{access as yc,readFile as wc,stat as xc}from"node:fs/promises";import Re from"node:path";var Mo=async e=>{try{return await yc(e),!0}catch{return!1}},bc=async e=>{try{return(await xc(e)).isDirectory()}catch{return!1}},Ut=async e=>{let t=[Re.join(e,"src","app"),Re.join(e,"app")];for(let r of t)if(await bc(r))return r;return null},vc=["next-pwa","@ducanh2912/next-pwa","@serwist/next","serwist"],Mr=async e=>{let t={isPwa:!1},r=[Re.join(e,"public","manifest.json"),Re.join(e,"public","manifest.webmanifest"),Re.join(e,"public","site.webmanifest")];for(let o of r)if(await Mo(o)){t.publicManifestPath=o,t.isPwa=!0;break}let n=await Ut(e);if(n)for(let o of["ts","tsx","js"]){let s=Re.join(n,`manifest.${o}`);if(await Mo(s)){t.appManifestPath=s,t.isPwa=!0;break}}try{let o=JSON.parse(await wc(Re.join(e,"package.json"),"utf-8")),s={...o.dependencies,...o.devDependencies};for(let i of vc)if(s[i]){t.framework=i,t.isPwa=!0;break}}catch{}return t};import{mkdir as Ec,readFile as Jo,stat as Tc,writeFile as Rc}from"node:fs/promises";import Y from"node:path";import jc from"sharp";import kc from"png-to-ico";import ut from"sharp";var _o=e=>e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;"),_r=(e,t,r)=>{switch(e){case"square":return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><rect width="${t}" height="${t}" fill="white"/></svg>`;case"circle":{let n=t/2;return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><circle cx="${n}" cy="${n}" r="${n}" fill="white"/></svg>`}case"rounded":{let n=Math.round(t*r/100);return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><rect width="${t}" height="${t}" rx="${n}" ry="${n}" fill="white"/></svg>`}case"squircle":return $c(t)}},$c=e=>{let t=e,r=t*.225,n=[`M 0 ${r}`,`C 0 0 0 0 ${r} 0`,`L ${t-r} 0`,`C ${t} 0 ${t} 0 ${t} ${r}`,`L ${t} ${t-r}`,`C ${t} ${t} ${t} ${t} ${t-r} ${t}`,`L ${r} ${t}`,`C 0 ${t} 0 ${t} 0 ${t-r}`,"Z"].join(" ");return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><path d="${_o(n)}" fill="white"/></svg>`},Do=(e,t)=>`<svg xmlns="http://www.w3.org/2000/svg" width="${e}" height="${e}"><rect width="${e}" height="${e}" fill="${_o(t)}"/></svg>`;var Ve=async e=>{let{size:t,paddingPercent:r,bg:n,fit:o,shape:s,radiusPercent:i,quality:a,forceSquare:c,sourceBuffer:l}=e,p=Math.max(1,Math.round(t*(1-r*2/100))),u=o==="cover"?"cover":"contain",f=await ut(l,{density:384}).resize(p,p,{fit:u,background:{r:0,g:0,b:0,alpha:0}}).png().toBuffer(),d=Math.round((t-p)/2),g=n==="transparent"?{r:0,g:0,b:0,alpha:0}:await Dr(n),y=await ut({create:{width:t,height:t,channels:4,background:g}}).composite([{input:f,left:d,top:d}]).png().toBuffer();if(!c&&(s!=="square"||o==="clip")){let x=s==="square"?"rounded":s,E=Buffer.from(_r(x,t,i));y=await ut(y).composite([{input:E,blend:"dest-in"}]).png({compressionLevel:Lo(a)}).toBuffer()}else y=await ut(y).png({compressionLevel:Lo(a)}).toBuffer();return y},Dr=async e=>{let t=await ut(Buffer.from(Do(1,e))).raw().toBuffer({resolveWithObject:!0}),[r,n,o,s=255]=t.data;return{r,g:n,b:o,alpha:s/255}},Lo=e=>{let t=Math.round((100-e)/100*9);return Math.max(0,Math.min(9,t))},Uo=async e=>{if(e.length===0)throw new Error("No frames provided to encodeIco");return kc(e)};import{readFile as Pc,writeFile as Xf}from"node:fs/promises";var Go=e=>e.map(({src:t,size:r})=>({src:t,sizes:`${r}x${r}`,type:"image/png",purpose:"any maskable"})),Bo=async(e,t)=>{let r=await Pc(e,"utf-8"),n=JSON.parse(r),o=Array.isArray(n.icons)?n.icons:[],s=new Map;for(let i of[...o,...t])i&&typeof i.src=="string"&&s.set(i.src,i);return n.icons=[...s.values()],`${JSON.stringify(n,null,2)}
623
+ `};var Vo=e=>`icons: [
624
624
  ${e.map(r=>` { src: '${r.src}', sizes: '${r.sizes}', type: '${r.type}'${r.purpose?`, purpose: '${r.purpose}'`:""} }`).join(`,
625
625
  `)},
626
- ],`,Mo=(e,t,r)=>`${JSON.stringify({name:e,short_name:e,start_url:"/",display:"standalone",background_color:"#ffffff",theme_color:t,icons:r},null,2)}
627
- `;import{stat as ac}from"node:fs/promises";import Ir from"node:path";var _o=[".png",".jpg",".jpeg",".webp",".svg",".avif"],Dt=async e=>{if(!e)throw new Error("Source image path is required (use --path).");let t=Ir.isAbsolute(e)?e:Ir.resolve(process.cwd(),e),r;try{r=await ac(t)}catch{throw new Error(`Source image not found: ${t}`)}if(!r.isFile())throw new Error(`Source is not a file: ${t}`);let n=Ir.extname(t).toLowerCase();if(!_o.includes(n))throw new Error(`Unsupported source format '${n}'. Use one of: ${_o.join(", ")}`);return{absolutePath:t,ext:n,bytes:r.size,isVector:n===".svg"}};var Nr=(e,t)=>{if(!e)return t;let r=e.split(",").map(n=>Number.parseInt(n.trim(),10)).filter(n=>Number.isFinite(n)&&n>0&&n<=1024);if(r.length===0)throw new Error(`Invalid --sizes value: '${e}'. Provide comma-separated positive integers.`);return r};var dc=async e=>{try{return await pc(e),!0}catch{return!1}},uc=async(e,t,r)=>{let n=[];for(let o of e){if(await dc(o.outPath)&&!t&&!o.alwaysWrite){n.push({path:o.outPath,bytes:o.bytes.length,skipped:!0});continue}r||(await cc(X.dirname(o.outPath),{recursive:!0}),await lc(o.outPath,o.bytes)),n.push({path:o.outPath,bytes:o.bytes.length})}return n},Fr=async(e,t)=>{let r=await Dt(t.source),n=await Do(r.absolutePath),o=t.ogSource?await Do((await Dt(t.ogSource)).absolutePath):n,s=[],i=[];for(let c of t.icoSizes)i.push(await Ge({sourceBuffer:n,size:c,shape:"square",radiusPercent:t.radius,bg:t.bg,paddingPercent:t.padding,fit:t.fit,quality:t.quality,forceSquare:!0}));let a=await Ao(i);if(s.push({outPath:X.join(t.outDir,"favicon.ico"),bytes:a}),t.emitIcon){let c=await Ge({sourceBuffer:n,size:512,shape:t.shape,radiusPercent:t.radius,bg:t.bg,paddingPercent:t.padding,fit:t.fit,quality:t.quality});s.push({outPath:X.join(t.outDir,"icon.png"),bytes:c})}if(t.emitApple){let c=t.bg==="transparent"?"#ffffff":t.bg,d=await Ge({sourceBuffer:n,size:180,shape:t.shape,radiusPercent:t.radius,bg:c,paddingPercent:t.padding,fit:t.fit,quality:t.quality});s.push({outPath:X.join(t.outDir,"apple-icon.png"),bytes:d})}if(t.emitOg){let c=await Lo(o,t,!1);s.push({outPath:X.join(t.outDir,"opengraph-image.png"),bytes:c})}if(t.emitTwitter){let c=await Lo(o,t,!0);s.push({outPath:X.join(t.outDir,"twitter-image.png"),bytes:c})}let p;if(t.pwa||t.pwaInit){let c=await Tr(e);if(t.pwa&&!c.isPwa)throw new Error("No PWA setup detected. Use --pwa-init to bootstrap a manifest, or set up next-pwa/serwist first.");let d=X.join(e,"public"),u=[192,512],f=[];for(let w of u){let P=await Ge({sourceBuffer:n,size:w,shape:t.shape,radiusPercent:t.radius,bg:t.bg,paddingPercent:t.padding,fit:t.fit,quality:t.quality}),b=`icon-${w}.png`;s.push({outPath:X.join(d,b),bytes:P}),f.push({src:`/${b}`,size:w})}let h=Io(f);if(c.publicManifestPath){let w=await No(c.publicManifestPath,h);s.push({outPath:c.publicManifestPath,bytes:Buffer.from(w,"utf-8"),alwaysWrite:!0})}else if(c.appManifestPath)p=Fo(h);else if(t.pwaInit){let w=X.join(d,"manifest.webmanifest"),P=Mo(X.basename(e)||"App","#000000",h);s.push({outPath:w,bytes:Buffer.from(P,"utf-8")})}}return{outputs:await uc(s,t.force,t.dryRun),pwaSnippet:p}},Lo=async(e,t,r)=>{let o=r?600:630,s=Math.round(Math.min(1200,o)*(1-t.padding*2/100)),i=await Ge({sourceBuffer:e,size:s,shape:t.shape,radiusPercent:t.radius,bg:"transparent",paddingPercent:0,fit:t.fit,quality:t.quality}),a=t.bg==="transparent"?"#ffffff":t.bg,p=await Ar(a),m=Math.round((1200-s)/2),c=Math.round((o-s)/2);return mc({create:{width:1200,height:o,channels:4,background:p}}).composite([{input:i,left:m,top:c}]).png().toBuffer()};var Uo=new Set(["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","green","greenyellow","grey","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"]);var fc=["square","rounded","circle","squircle"],gc=["contain","cover","clip"],Go=(e,t,r,n)=>{if(!e)return r;if(!t.includes(e))throw new Error(`Invalid value for --${n}: '${e}'. Allowed: ${t.join(", ")}`);return e},Mr=(e,t,r,n,o)=>{if(e===void 0)return t;let s=Number(e);if(!Number.isFinite(s)||s<n||s>o)throw new Error(`Invalid value for --${r}: '${e}'. Must be a number between ${n}\u2013${o}.`);return s},Vo=e=>{e.command("favicon").description("Generate favicon.ico (and optionally icons, OG image, PWA manifest icons)").option("--path <file>","Path to source image (PNG, JPG, JPEG, WebP, SVG, AVIF)").option("--out <dir>","Output dir (default: src/app or app)").option("--force","Overwrite existing files without prompt",!1).option("--dry-run","Show what would be written without writing",!1).option("--icon","Also emit icon.png (512\xD7512)",!1).option("--apple","Also emit apple-icon.png (180\xD7180)",!1).option("--og","Also emit opengraph-image.png (1200\xD7630)",!1).option("--og-source <file>","Use a separate image for the OG/Twitter card").option("--twitter","Also emit twitter-image.png (1200\xD7600)",!1).option("--all","Shorthand for --icon --apple --og",!1).option("--pwa","Detect PWA setup and emit manifest icons (192/512); errors if not detected",!1).option("--pwa-init","Bootstrap public/manifest.webmanifest with icons",!1).option("--shape <shape>","square | rounded | circle | squircle","square").option("--radius <percent>","Corner radius % when shape=rounded (0-50)","20").option("--bg <color>",'Background color (hex, css name, or "transparent")',"transparent").option("--padding <percent>","Padding around source content (0-30)","0").option("--fit <fit>","How source fits target: contain | cover | clip","contain").option("--sizes <list>","Comma-separated ICO sizes (default: 16,32,48)").option("--quality <n>","PNG compression 1-100 (higher = smaller file; PNG is lossless, default: 90)","90").action(async t=>{try{let r=process.cwd();l(Re.cyan(`
626
+ ],`,Ho=(e,t,r)=>`${JSON.stringify({name:e,short_name:e,start_url:"/",display:"standalone",background_color:"#ffffff",theme_color:t,icons:r},null,2)}
627
+ `;import{stat as Sc}from"node:fs/promises";import Lr from"node:path";var qo=[".png",".jpg",".jpeg",".webp",".svg",".avif"],Gt=async e=>{if(!e)throw new Error("Source image path is required (use --path).");let t=Lr.isAbsolute(e)?e:Lr.resolve(process.cwd(),e),r;try{r=await Sc(t)}catch{throw new Error(`Source image not found: ${t}`)}if(!r.isFile())throw new Error(`Source is not a file: ${t}`);let n=Lr.extname(t).toLowerCase();if(!qo.includes(n))throw new Error(`Unsupported source format '${n}'. Use one of: ${qo.join(", ")}`);return{absolutePath:t,ext:n,bytes:r.size,isVector:n===".svg"}};var Ur=(e,t)=>{if(!e)return t;let r=e.split(",").map(n=>Number.parseInt(n.trim(),10)).filter(n=>Number.isFinite(n)&&n>0&&n<=1024);if(r.length===0)throw new Error(`Invalid --sizes value: '${e}'. Provide comma-separated positive integers.`);return r};var Cc=async e=>{try{return await Tc(e),!0}catch{return!1}},Oc=async(e,t,r)=>{let n=[];for(let o of e){if(await Cc(o.outPath)&&!t&&!o.alwaysWrite){n.push({path:o.outPath,bytes:o.bytes.length,skipped:!0});continue}r||(await Ec(Y.dirname(o.outPath),{recursive:!0}),await Rc(o.outPath,o.bytes)),n.push({path:o.outPath,bytes:o.bytes.length})}return n},Gr=async(e,t)=>{let r=await Gt(t.source),n=await Jo(r.absolutePath),o=t.ogSource?await Jo((await Gt(t.ogSource)).absolutePath):n,s=[],i=[];for(let p of t.icoSizes)i.push(await Ve({sourceBuffer:n,size:p,shape:"square",radiusPercent:t.radius,bg:t.bg,paddingPercent:t.padding,fit:t.fit,quality:t.quality,forceSquare:!0}));let a=await Uo(i);if(s.push({outPath:Y.join(t.outDir,"favicon.ico"),bytes:a}),t.emitIcon){let p=await Ve({sourceBuffer:n,size:512,shape:t.shape,radiusPercent:t.radius,bg:t.bg,paddingPercent:t.padding,fit:t.fit,quality:t.quality});s.push({outPath:Y.join(t.outDir,"icon.png"),bytes:p})}if(t.emitApple){let p=t.bg==="transparent"?"#ffffff":t.bg,u=await Ve({sourceBuffer:n,size:180,shape:t.shape,radiusPercent:t.radius,bg:p,paddingPercent:t.padding,fit:t.fit,quality:t.quality});s.push({outPath:Y.join(t.outDir,"apple-icon.png"),bytes:u})}if(t.emitOg){let p=await zo(o,t,!1);s.push({outPath:Y.join(t.outDir,"opengraph-image.png"),bytes:p})}if(t.emitTwitter){let p=await zo(o,t,!0);s.push({outPath:Y.join(t.outDir,"twitter-image.png"),bytes:p})}let c;if(t.pwa||t.pwaInit){let p=await Mr(e);if(t.pwa&&!p.isPwa)throw new Error("No PWA setup detected. Use --pwa-init to bootstrap a manifest, or set up next-pwa/serwist first.");let u=Y.join(e,"public"),f=[192,512],d=[];for(let y of f){let S=await Ve({sourceBuffer:n,size:y,shape:t.shape,radiusPercent:t.radius,bg:t.bg,paddingPercent:t.padding,fit:t.fit,quality:t.quality}),x=`icon-${y}.png`;s.push({outPath:Y.join(u,x),bytes:S}),d.push({src:`/${x}`,size:y})}let g=Go(d);if(p.publicManifestPath){let y=await Bo(p.publicManifestPath,g);s.push({outPath:p.publicManifestPath,bytes:Buffer.from(y,"utf-8"),alwaysWrite:!0})}else if(p.appManifestPath)c=Vo(g);else if(t.pwaInit){let y=Y.join(u,"manifest.webmanifest"),S=Ho(Y.basename(e)||"App","#000000",g);s.push({outPath:y,bytes:Buffer.from(S,"utf-8")})}}return{outputs:await Oc(s,t.force,t.dryRun),pwaSnippet:c}},zo=async(e,t,r)=>{let o=r?600:630,s=Math.round(Math.min(1200,o)*(1-t.padding*2/100)),i=await Ve({sourceBuffer:e,size:s,shape:t.shape,radiusPercent:t.radius,bg:"transparent",paddingPercent:0,fit:t.fit,quality:t.quality}),a=t.bg==="transparent"?"#ffffff":t.bg,c=await Dr(a),l=Math.round((1200-s)/2),p=Math.round((o-s)/2);return jc({create:{width:1200,height:o,channels:4,background:c}}).composite([{input:i,left:l,top:p}]).png().toBuffer()};var Wo=new Set(["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","green","greenyellow","grey","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"]);var Ac=["square","rounded","circle","squircle"],Ic=["contain","cover","clip"],Ko=(e,t,r,n)=>{if(!e)return r;if(!t.includes(e))throw new Error(`Invalid value for --${n}: '${e}'. Allowed: ${t.join(", ")}`);return e},Br=(e,t,r,n,o)=>{if(e===void 0)return t;let s=Number(e);if(!Number.isFinite(s)||s<n||s>o)throw new Error(`Invalid value for --${r}: '${e}'. Must be a number between ${n}\u2013${o}.`);return s},Yo=e=>{e.command("favicon").description("Generate favicon.ico (and optionally icons, OG image, PWA manifest icons)").option("--path <file>","Path to source image (PNG, JPG, JPEG, WebP, SVG, AVIF)").option("--out <dir>","Output dir (default: src/app or app)").option("--force","Overwrite existing files without prompt",!1).option("--dry-run","Show what would be written without writing",!1).option("--icon","Also emit icon.png (512\xD7512)",!1).option("--apple","Also emit apple-icon.png (180\xD7180)",!1).option("--og","Also emit opengraph-image.png (1200\xD7630)",!1).option("--og-source <file>","Use a separate image for the OG/Twitter card").option("--twitter","Also emit twitter-image.png (1200\xD7600)",!1).option("--all","Shorthand for --icon --apple --og",!1).option("--pwa","Detect PWA setup and emit manifest icons (192/512); errors if not detected",!1).option("--pwa-init","Bootstrap public/manifest.webmanifest with icons",!1).option("--shape <shape>","square | rounded | circle | squircle","square").option("--radius <percent>","Corner radius % when shape=rounded (0-50)","20").option("--bg <color>",'Background color (hex, css name, or "transparent")',"transparent").option("--padding <percent>","Padding around source content (0-30)","0").option("--fit <fit>","How source fits target: contain | cover | clip","contain").option("--sizes <list>","Comma-separated ICO sizes (default: 16,32,48)").option("--quality <n>","PNG compression 1-100 (higher = smaller file; PNG is lossless, default: 90)","90").action(async t=>{try{let r=process.cwd();m(je.cyan(`
628
628
  \u{1F3A8} Favicon Generator
629
- `));let n=await Ro({source:t.path}),o=await hc(r,t.out),s=Go(t.shape,fc,"square","shape"),i=Go(t.fit,gc,"contain","fit"),a=Mr(t.radius,20,"radius",0,50),p=Mr(t.padding,0,"padding",0,30),m=Mr(t.quality,90,"quality",1,100),c=Nr(t.sizes,[16,32,48]),d=t.bg??"transparent";xc(d);let u=t.all===!0,f={source:n.source,outDir:o,force:!!t.force,dryRun:!!t.dryRun,emitIcon:!!t.icon||u,emitApple:!!t.apple||u,emitOg:!!t.og||u,emitTwitter:!!t.twitter,ogSource:t.ogSource,pwa:!!t.pwa,pwaInit:!!t.pwaInit,shape:s,radius:a,bg:d,padding:p,fit:i,icoSizes:c,quality:m};g.start("Generating favicon assets...");let h=await Fr(r,f);g.succeed(f.dryRun?"Favicon plan ready":"Favicon assets generated"),l("");for(let w of h.outputs){let P=Lt.relative(r,w.path);w.skipped?l(Re.yellow(` \u21B7 skipped ${P} (exists; use --force to overwrite)`)):f.dryRun?l(Re.dim(` \u{1F4C4} would write ${P} (${Bo(w.bytes)})`)):l(Re.green(` \u2713 ${P} `)+Re.dim(`(${Bo(w.bytes)})`))}h.pwaSnippet&&(l(""),l(Re.cyan("Add this to your typed manifest (src/app/manifest.ts):")),l(Re.dim(h.pwaSnippet))),l("")}catch(r){g.fail("Favicon generation failed");let n=r instanceof Error?r.message:String(r);x(n),process.exit(1)}})},hc=async(e,t)=>{if(t)return Lt.isAbsolute(t)?t:Lt.resolve(e,t);let r=await _t(e);return r||(cn("Could not detect app/ or src/app/ \u2014 falling back to src/app"),Lt.join(e,"src","app"))},yc=/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,wc=/^(?:rgb|rgba|hsl|hsla)\(\s*[\d.,%\s/]+\)$/i,xc=e=>{if(e!=="transparent"&&!yc.test(e)&&!wc.test(e)&&!Uo.has(e.toLowerCase()))throw new Error(`Invalid value for --bg: '${e}'. Use 'transparent', a hex code (e.g. #0f172a), a CSS color name, or rgb()/rgba()/hsl()/hsla().`)},Bo=e=>e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(2)} MB`;import _r from"node:path";import _ from"picocolors";import bc from"enquirer";var{prompt:vc}=bc,qo=async(e,t,r={})=>{let n=[];e||n.push({type:"input",name:"featureName",message:"Feature name (kebab-case):",initial:"my-feature",validate:s=>/^[a-z][a-z0-9-]*$/.test(s)||"Use lowercase letters, digits, and hyphens only."}),r.api===void 0&&n.push({type:"confirm",name:"createApi",message:"Generate the api/ layer (schema, DAL, Server Actions, queries)?",initial:!0}),t!=="none"&&r.store===void 0&&(n.push({type:"confirm",name:"createStore",message:`Generate a ${t==="zustand"?"Zustand":"Redux"} slice for client-only state?`,initial:!1}),t==="redux"&&r.persist===void 0&&n.push({type:"confirm",name:"persistStore",message:"Persist the slice across reloads?",initial:!1,skip(){return!this.state.answers.createStore}}));let o=n.length>0?await vc(n):{};return{featureName:e??o.featureName,createApi:r.api??o.createApi??!0,createStore:t!=="none"&&(r.store??o.createStore??!1),persistStore:t==="redux"&&(r.persist??o.persistStore??!1)}};var zo=e=>{e.command("feature [name]").description("Generate a feature module (api/, components/, store/, index.ts, server.ts)").option("--api","Generate the api/ layer: schema, DAL, Server Actions, queries").option("--no-api","Skip the api/ layer").option("--store","Generate a client-state slice (Redux or Zustand, whichever the project uses)").option("--no-store","Skip the slice").option("--persist","Persist the Redux slice across reloads").option("--no-persist","Do not persist the slice").option("--path <path>","Base directory (default: src/features)").action(async(t,r)=>{try{let n=process.cwd();l(_.cyan(`
629
+ `));let n=await Fo({source:t.path}),o=await Nc(r,t.out),s=Ko(t.shape,Ac,"square","shape"),i=Ko(t.fit,Ic,"contain","fit"),a=Br(t.radius,20,"radius",0,50),c=Br(t.padding,0,"padding",0,30),l=Br(t.quality,90,"quality",1,100),p=Ur(t.sizes,[16,32,48]),u=t.bg??"transparent";_c(u);let f=t.all===!0,d={source:n.source,outDir:o,force:!!t.force,dryRun:!!t.dryRun,emitIcon:!!t.icon||f,emitApple:!!t.apple||f,emitOg:!!t.og||f,emitTwitter:!!t.twitter,ogSource:t.ogSource,pwa:!!t.pwa,pwaInit:!!t.pwaInit,shape:s,radius:a,bg:u,padding:c,fit:i,icoSizes:p,quality:l};h.start("Generating favicon assets...");let g=await Gr(r,d);h.succeed(d.dryRun?"Favicon plan ready":"Favicon assets generated"),m("");for(let y of g.outputs){let S=Bt.relative(r,y.path);y.skipped?m(je.yellow(` \u21B7 skipped ${S} (exists; use --force to overwrite)`)):d.dryRun?m(je.dim(` \u{1F4C4} would write ${S} (${Xo(y.bytes)})`)):m(je.green(` \u2713 ${S} `)+je.dim(`(${Xo(y.bytes)})`))}g.pwaSnippet&&(m(""),m(je.cyan("Add this to your typed manifest (src/app/manifest.ts):")),m(je.dim(g.pwaSnippet))),m("")}catch(r){h.fail("Favicon generation failed");let n=r instanceof Error?r.message:String(r);b(n),process.exit(1)}})},Nc=async(e,t)=>{if(t)return Bt.isAbsolute(t)?t:Bt.resolve(e,t);let r=await Ut(e);return r||(hn("Could not detect app/ or src/app/ \u2014 falling back to src/app"),Bt.join(e,"src","app"))},Fc=/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,Mc=/^(?:rgb|rgba|hsl|hsla)\(\s*[\d.,%\s/]+\)$/i,_c=e=>{if(e!=="transparent"&&!Fc.test(e)&&!Mc.test(e)&&!Wo.has(e.toLowerCase()))throw new Error(`Invalid value for --bg: '${e}'. Use 'transparent', a hex code (e.g. #0f172a), a CSS color name, or rgb()/rgba()/hsl()/hsla().`)},Xo=e=>e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(2)} MB`;import Vr from"node:path";import D from"picocolors";import Dc from"enquirer";var{prompt:Lc}=Dc,Qo=async(e,t,r={})=>{let n=[];e||n.push({type:"input",name:"featureName",message:"Feature name (kebab-case):",initial:"my-feature",validate:s=>/^[a-z][a-z0-9-]*$/.test(s)||"Use lowercase letters, digits, and hyphens only."}),r.api===void 0&&n.push({type:"confirm",name:"createApi",message:"Generate the api/ layer (schema, DAL, Server Actions, queries)?",initial:!0}),t!=="none"&&r.store===void 0&&(n.push({type:"confirm",name:"createStore",message:`Generate a ${t==="zustand"?"Zustand":"Redux"} slice for client-only state?`,initial:!1}),t==="redux"&&r.persist===void 0&&n.push({type:"confirm",name:"persistStore",message:"Persist the slice across reloads?",initial:!1,skip(){return!this.state.answers.createStore}}));let o=n.length>0?await Lc(n):{};return{featureName:e??o.featureName,createApi:r.api??o.createApi??!0,createStore:t!=="none"&&(r.store??o.createStore??!1),persistStore:t==="redux"&&(r.persist??o.persistStore??!1)}};var es=e=>{e.command("feature [name]").description("Generate a feature module (api/, components/, store/, index.ts, server.ts)").option("--api","Generate the api/ layer: schema, DAL, Server Actions, queries").option("--no-api","Skip the api/ layer").option("--store","Generate a client-state slice (Redux or Zustand, whichever the project uses)").option("--no-store","Skip the slice").option("--persist","Persist the Redux slice across reloads").option("--no-persist","Do not persist the slice").option("--path <path>","Base directory (default: src/features)").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(D.cyan(`
630
630
  \u{1F3AF} Feature Generator
631
- `)),g.start("Detecting project setup...");let o=await T(n);g.succeed("Project setup detected"),l(_.dim(` state: ${o.state} i18n: ${o.hasI18n?"\u2713":"\u2717"} tests: ${o.hasTests?"\u2713":"\u2717"}
632
- `));let s=await qo(t,o.state,{api:r.api,store:r.store,persist:r.persist});F(s.featureName,"feature name"),r.path&&W(r.path,"path");let i=r.path||_r.join("src","features"),a=te(n,i,s.featureName);await ve(n,s.featureName,i)&&(x(`Feature '${s.featureName}' already exists at ${i}.`),process.exit(1)),g.start("Generating feature files..."),await dr({name:s.featureName,outputPath:a,createStore:s.createStore,persistStore:s.persistStore,createApi:s.createApi,state:o.state,hasI18n:o.hasI18n,hasTests:o.hasTests}),g.succeed("Feature files generated"),o.hasI18n&&await Se(n,$(s.featureName)),s.createApi&&(g.start("Registering API endpoints..."),await ct({serviceName:s.featureName,projectPath:n}),g.succeed("API endpoints registered")),s.createStore&&o.state==="redux"&&(g.start("Registering slice in the store..."),await pt({projectPath:n,name:s.featureName,persist:s.persistStore,importPath:_r.join(i,s.featureName,"store")}),g.succeed("Slice registered")),$c(s,i,o.state)}catch(n){g.fail("Feature generation failed"),x(`${n instanceof Error?n.message:n}`),process.exit(1)}})},$c=(e,t,r)=>{let n=_r.join(t,e.featureName);l(_.green(`
631
+ `)),h.start("Detecting project setup...");let s=await O(n);h.succeed("Project setup detected"),m(D.dim(` state: ${s.state} i18n: ${s.hasI18n?"\u2713":"\u2717"} tests: ${s.hasTests?"\u2713":"\u2717"}
632
+ `));let i=await Qo(t,s.state,{api:r.api,store:r.store,persist:r.persist});M(i.featureName,"feature name"),r.path&&W(r.path,"path");let a=r.path||Vr.join("src","features"),c=ne(n,a,i.featureName);await ke(n,i.featureName,a)&&(b(`Feature '${i.featureName}' already exists at ${a}.`),process.exit(1)),h.start("Generating feature files..."),await wr({name:i.featureName,outputPath:c,createStore:i.createStore,persistStore:i.persistStore,createApi:i.createApi,state:s.state,hasI18n:s.hasI18n,hasTests:s.hasTests}),h.succeed("Feature files generated"),s.hasI18n&&await Te(n,$(i.featureName)),i.createApi&&(h.start("Registering API endpoints..."),await lt({serviceName:i.featureName,projectPath:n}),h.succeed("API endpoints registered")),i.createStore&&s.state==="redux"&&(h.start("Registering slice in the store..."),await mt({projectPath:n,name:i.featureName,persist:i.persistStore,importPath:Vr.join(a,i.featureName,"store")}),h.succeed("Slice registered")),await k(n,o),Uc(i,a,s.state)}catch(n){h.fail("Feature generation failed"),b(`${n instanceof Error?n.message:n}`),process.exit(1)}})},Uc=(e,t,r)=>{let n=Vr.join(t,e.featureName);m(D.green(`
633
633
  \u2728 Feature '${e.featureName}' created.
634
- `)),l(_.dim(` ${n}/`)),e.createApi&&l(_.dim(" api/ schema, keys, server (DAL), actions, queries")),l(_.dim(" components/")),e.createApi||l(_.dim(" hooks/")),e.createStore&&l(_.dim(" store/")),l(_.dim(" types/")),l(_.dim(" index.ts client-safe barrel")),e.createApi&&l(_.dim(" server.ts server-only barrel")),l(""),l(_.cyan("Next:")),e.createApi&&(l(_.dim(` 1. Adjust the contracts in ${n}/api/schema.ts and the paths in src/lib/config/app-apis.ts`)),l(_.dim(` 2. Read in a Server Component: import { list${Jo(e.featureName)}s } from '@/features/${e.featureName}/server'`)),l(_.dim(` 3. Prefetch + hydrate for the client list: prefetchQuery(${Pc(e.featureName)}ListQuery())`))),e.createStore&&r==="zustand"&&l(_.yellow(` ! Compose create${Jo(e.featureName)}Slice into AppState in src/store/index.ts`)),l("")},Pc=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),Jo=$;import Dr from"node:path";import Be from"picocolors";import kc from"enquirer";var{prompt:Sc}=kc,Wo=async e=>e?{hookName:e}:await Sc({type:"input",name:"hookName",message:'Hook name (kebab-case, without "use" prefix):',validate:r=>r?/^[a-z][a-z0-9-]*$/.test(r)?!0:"Use lowercase letters, numbers, and hyphens only":"Hook name is required"});var Ho=e=>{e.command("hook [name]").description("Generate a custom React hook").option("--client","Add 'use client' directive (default: true)",!0).option("--feature <path>","Generate in feature directory (e.g., src/features/auth)").option("--test","Also generate a sibling test file").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd();l(Be.cyan(`
634
+ `)),m(D.dim(` ${n}/`)),e.createApi&&m(D.dim(" api/ schema, keys, server (DAL), actions, queries")),m(D.dim(" components/")),e.createApi||m(D.dim(" hooks/")),e.createStore&&m(D.dim(" store/")),m(D.dim(" types/")),m(D.dim(" index.ts client-safe barrel")),e.createApi&&m(D.dim(" server.ts server-only barrel")),m(""),m(D.cyan("Next:")),e.createApi&&(m(D.dim(` 1. Adjust the contracts in ${n}/api/schema.ts and the paths in src/lib/config/app-apis.ts`)),m(D.dim(` 2. Read in a Server Component: import { list${Zo(e.featureName)}s } from '@/features/${e.featureName}/server'`)),m(D.dim(` 3. Prefetch + hydrate for the client list: prefetchQuery(${Gc(e.featureName)}ListQuery())`))),e.createStore&&r==="zustand"&&m(D.yellow(` ! Compose create${Zo(e.featureName)}Slice into AppState in src/store/index.ts`)),m("")},Gc=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),Zo=$;import Hr from"node:path";import He from"picocolors";import Bc from"enquirer";var{prompt:Vc}=Bc,ts=async e=>e?{hookName:e}:await Vc({type:"input",name:"hookName",message:'Hook name (kebab-case, without "use" prefix):',validate:r=>r?/^[a-z][a-z0-9-]*$/.test(r)?!0:"Use lowercase letters, numbers, and hyphens only":"Hook name is required"});var rs=e=>{e.command("hook [name]").description("Generate a custom React hook").option("--client","Add 'use client' directive (default: true)",!0).option("--feature <path>","Generate in feature directory (e.g., src/features/auth)").option("--test","Also generate a sibling test file").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(He.cyan(`
635
635
  \u{1FA9D} Hook Generator
636
- `));let o=await T(n),s=await Wo(t);F(s.hookName,"hook name"),r.feature&&W(r.feature,"feature path");let a=`use${$(s.hookName)}`,p=Ec(r,o.hasTests);g.start("Generating hook..."),await fr({name:s.hookName,projectPath:n,isClient:r.client??!0,featurePath:r.feature}),g.succeed("Hook generated");let m=r.feature?Dr.join(n,r.feature,"hooks",`${a}.ts`):Dr.join(n,"src/hooks",`${a}.ts`),c=null;p&&(g.start("Generating test..."),c=await re({projectPath:n,sourceFile:m,kind:"hook",symbolName:a,hookUsesStore:o.state!=="none"&&!!r.feature}),g.succeed("Test generated"));let d=r.feature?`${r.feature}/hooks/${a}.ts`:`src/hooks/${a}.ts`;l(Be.green(`
637
- \u2728 Hook '${a}' created successfully!
638
- `)),l(Be.dim(` \u{1F4C4} ${d}`)),c&&l(Be.dim(` \u{1F9EA} ${Dr.relative(n,c)}`)),l(""),l(Be.cyan("Usage:"));let u=r.feature?`${r.feature.replace(/^src\//,"@/")}/hooks/${a}`:`@/hooks/${a}`;l(Be.dim(` import { ${a} } from '${u}';`)),l("")}catch(n){g.fail("Hook generation failed"),x(`${n}`),process.exit(1)}})},Ec=(e,t)=>e.test===!1?!1:e.test===!0?!0:t;import Ut from"picocolors";var Ko=e=>{e.command("layout <segment>").description("Generate a nested layout.tsx (locale-aware when i18n is detected)").option("--group","Treat the segment as a route group (wraps it in parens)").option("--at <path>","Place the layout under this nested path (kebab-case, slash-separated)").option("--no-locale","Skip the locale wrapper even if i18n is detected").action(async(t,r)=>{try{let n=process.cwd();l(Ut.cyan(`
636
+ `));let s=await O(n),i=await ts(t);M(i.hookName,"hook name"),r.feature&&W(r.feature,"feature path");let c=`use${$(i.hookName)}`,l=Hc(r,s.hasTests);h.start("Generating hook..."),await br({name:i.hookName,projectPath:n,isClient:r.client??!0,featurePath:r.feature}),h.succeed("Hook generated");let p=r.feature?Hr.join(n,r.feature,"hooks",`${c}.ts`):Hr.join(n,"src/hooks",`${c}.ts`),u=null;l&&(h.start("Generating test..."),u=await oe({projectPath:n,sourceFile:p,kind:"hook",symbolName:c,hookUsesStore:s.state!=="none"&&!!r.feature}),h.succeed("Test generated"));let f=r.feature?`${r.feature}/hooks/${c}.ts`:`src/hooks/${c}.ts`;await k(n,o),m(He.green(`
637
+ \u2728 Hook '${c}' created successfully!
638
+ `)),m(He.dim(` \u{1F4C4} ${f}`)),u&&m(He.dim(` \u{1F9EA} ${Hr.relative(n,u)}`)),m(""),m(He.cyan("Usage:"));let d=r.feature?`${r.feature.replace(/^src\//,"@/")}/hooks/${c}`:`@/hooks/${c}`;m(He.dim(` import { ${c} } from '${d}';`)),m("")}catch(n){h.fail("Hook generation failed"),b(`${n}`),process.exit(1)}})},Hc=(e,t)=>e.test===!1?!1:e.test===!0?!0:t;import Vt from"picocolors";var ns=e=>{e.command("layout <segment>").description("Generate a nested layout.tsx (locale-aware when i18n is detected)").option("--group","Treat the segment as a route group (wraps it in parens)").option("--at <path>","Place the layout under this nested path (kebab-case, slash-separated)").option("--no-locale","Skip the locale wrapper even if i18n is detected").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(Vt.cyan(`
639
639
  \u{1F4D0} Layout Generator
640
- `)),g.start("Detecting project setup...");let o=await T(n);g.succeed("Project setup detected");let s=o.hasI18n&&r.locale!==!1;l(Ut.dim(` i18n: ${s?"\u2713":"\u2717"}
641
- `)),g.start("Generating layout...");let i=await gr({segment:t,at:r.at,projectPath:n,hasI18n:s,withGroup:!!r.group});g.succeed("Layout generated"),l(Ut.green(`
642
- \u2728 ${i.componentName} created!
643
- `)),l(Ut.dim(` \u{1F4C4} ${i.displayPath}`)),l("")}catch(n){g.fail("Layout generation failed"),x(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import Y from"picocolors";import Rc from"enquirer";var{prompt:jc}=Rc,Xo=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"code",message:"Locale code (e.g., es, fr, de):",validate:o=>o?/^[a-z]{2}(-[A-Z]{2})?$/.test(o)?!0:"Use format: xx or xx-XX (e.g., es, pt-BR)":"Locale code is required"}),t.name||r.push({type:"input",name:"name",message:"Language name (e.g., Spanish, French):",validate:o=>o?!0:"Language name is required"}),t.country||r.push({type:"input",name:"country",message:"Country (e.g., Spain, France):",validate:o=>o?!0:"Country is required"}),t.flag||r.push({type:"input",name:"flag",message:"Flag emoji (e.g., \u{1F1EA}\u{1F1F8}, \u{1F1EB}\u{1F1F7}):",validate:o=>o?!0:"Flag emoji is required"}),t.copyTranslations===void 0&&r.push({type:"confirm",name:"copyTranslations",message:"Copy translations from English? (No = empty values)",initial:!1});let n=r.length>0?await jc(r):{};return{code:e??n.code,name:t.name??n.name,country:t.country??n.country,flag:t.flag??n.flag,copyTranslations:t.copyTranslations??n.copyTranslations??!1}};var Yo=e=>{e.command("locale [code]").description("Add a new locale/language").option("--copy-translations","Copy translations from English instead of empty values").option("--name <name>","Language name, e.g. Spanish").option("--country <country>","Country, e.g. Spain").option("--flag <emoji>","Flag emoji, e.g. \u{1F1EA}\u{1F1F8}").action(async(t,r)=>{try{let n=process.cwd();l(Y.cyan(`
640
+ `)),h.start("Detecting project setup...");let s=await O(n);h.succeed("Project setup detected");let i=s.hasI18n&&r.locale!==!1;m(Vt.dim(` i18n: ${i?"\u2713":"\u2717"}
641
+ `)),h.start("Generating layout...");let a=await vr({segment:t,at:r.at,projectPath:n,hasI18n:i,withGroup:!!r.group});h.succeed("Layout generated"),await k(n,o),m(Vt.green(`
642
+ \u2728 ${a.componentName} created!
643
+ `)),m(Vt.dim(` \u{1F4C4} ${a.displayPath}`)),m("")}catch(n){h.fail("Layout generation failed"),b(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import Q from"picocolors";import qc from"enquirer";var{prompt:Jc}=qc,os=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"code",message:"Locale code (e.g., es, fr, de):",validate:o=>o?/^[a-z]{2}(-[A-Z]{2})?$/.test(o)?!0:"Use format: xx or xx-XX (e.g., es, pt-BR)":"Locale code is required"}),t.name||r.push({type:"input",name:"name",message:"Language name (e.g., Spanish, French):",validate:o=>o?!0:"Language name is required"}),t.country||r.push({type:"input",name:"country",message:"Country (e.g., Spain, France):",validate:o=>o?!0:"Country is required"}),t.flag||r.push({type:"input",name:"flag",message:"Flag emoji (e.g., \u{1F1EA}\u{1F1F8}, \u{1F1EB}\u{1F1F7}):",validate:o=>o?!0:"Flag emoji is required"}),t.copyTranslations===void 0&&r.push({type:"confirm",name:"copyTranslations",message:"Copy translations from English? (No = empty values)",initial:!1});let n=r.length>0?await Jc(r):{};return{code:e??n.code,name:t.name??n.name,country:t.country??n.country,flag:t.flag??n.flag,copyTranslations:t.copyTranslations??n.copyTranslations??!1}};var ss=e=>{e.command("locale [code]").description("Add a new locale/language").option("--copy-translations","Copy translations from English instead of empty values").option("--name <name>","Language name, e.g. Spanish").option("--country <country>","Country, e.g. Spain").option("--flag <emoji>","Flag emoji, e.g. \u{1F1EA}\u{1F1F8}").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(Q.cyan(`
644
644
  \u{1F30D} Locale Generator
645
- `)),g.start("Detecting project setup...");let o=await T(n);g.succeed("Project setup detected"),o.hasI18n||(g.fail("i18n is not set up in this project"),x("Please set up internationalization first"),l(Y.dim(`
645
+ `)),h.start("Detecting project setup...");let s=await O(n);h.succeed("Project setup detected"),s.hasI18n||(h.fail("i18n is not set up in this project"),b("Please set up internationalization first"),m(Q.dim(`
646
646
  Run: npx @teispace/next-maker setup --i18n
647
- `)),process.exit(1));let s=await Xo(t,{copyTranslations:r.copyTranslations,name:r.name,country:r.country,flag:r.flag});F(s.code,"locale code");let i=te(n,"src","i18n","translations",`${s.code}.json`);y(i)&&(x(`Locale '${s.code}' already exists!`),process.exit(1)),g.start("Adding locale..."),await hr({...s,projectPath:n}),g.succeed("Locale added"),l(Y.green(`
648
- \u2728 Locale '${s.code}' (${s.name}) added successfully!
649
- `)),l(Y.dim("Updated files:")),l(Y.dim(` \u{1F4C4} src/i18n/translations/${s.code}.json`)),l(Y.dim(" \u{1F4DD} src/types/i18n.ts (SupportedLocale type)")),l(Y.dim(" \u{1F4DD} src/lib/config/app-locales.ts")),l(""),l(Y.cyan("Next steps:")),l(Y.dim(` 1. Translate: src/i18n/translations/${s.code}.json`)),l(Y.dim(` 2. Visit: http://localhost:3000/${s.code}`)),l("")}catch(n){g.fail("Locale generation failed"),x(`${n}`),process.exit(1)}})};import Cc from"node:path";import mt from"picocolors";var Qo=e=>{e.command("options").description("List the starter's options and this project's current values").option("--starter-path <dir>","Read the manifest from a local starter checkout").action(async t=>{let r;try{let n=process.cwd(),o=y(Cc.join(n,".next-maker.json")),s=o?await ee(n):{cli:"",starter:{name:"",version:"",source:""},packageManager:"pnpm",answers:{}},i=await Me(s,{starterPath:t.starterPath});r=i.dispose,l(mt.cyan(`
647
+ `)),process.exit(1));let i=await os(t,{copyTranslations:r.copyTranslations,name:r.name,country:r.country,flag:r.flag});M(i.code,"locale code");let a=ne(n,"src","i18n","translations",`${i.code}.json`);w(a)&&(b(`Locale '${i.code}' already exists!`),process.exit(1)),h.start("Adding locale..."),await $r({...i,projectPath:n}),h.succeed("Locale added"),await k(n,o),m(Q.green(`
648
+ \u2728 Locale '${i.code}' (${i.name}) added successfully!
649
+ `)),m(Q.dim("Updated files:")),m(Q.dim(` \u{1F4C4} src/i18n/translations/${i.code}.json`)),m(Q.dim(" \u{1F4DD} src/types/i18n.ts (SupportedLocale type)")),m(Q.dim(" \u{1F4DD} src/lib/config/app-locales.ts")),m(""),m(Q.cyan("Next steps:")),m(Q.dim(` 1. Translate: src/i18n/translations/${i.code}.json`)),m(Q.dim(` 2. Visit: http://localhost:3000/${i.code}`)),m("")}catch(n){h.fail("Locale generation failed"),b(`${n}`),process.exit(1)}})};import zc from"node:path";import dt from"picocolors";var is=e=>{e.command("options").description("List the starter's options and this project's current values").option("--starter-path <dir>","Read the manifest from a local starter checkout").action(async t=>{let r;try{let n=process.cwd(),o=w(zc.join(n,".next-maker.json")),s=o?await re(n):{cli:"",starter:{name:"",version:"",source:""},packageManager:"pnpm",answers:{}},i=await De(s,{starterPath:t.starterPath});r=i.dispose,m(dt.cyan(`
650
650
  ${i.manifest.starter.name} ${i.manifest.starter.version}
651
- `));for(let[a,p]of Object.entries(i.manifest.options)){let m=o?s.answers[a]:p.default,c=p.type==="boolean"?"true | false":(p.values??[]).join(" | ");l(` ${mt.bold(a.padEnd(18))} ${String(Array.isArray(m)?m.join(",")||"none":m).padEnd(10)} ${mt.dim(c)}`),p.label&&l(` ${"".padEnd(18)} ${mt.dim(p.label)}`)}l(""),l(mt.dim(o?"Change with: next-maker setup --set <option>=<value>":"Use with: next-maker init --set <option>=<value>")),l("")}catch(n){x(`${n instanceof Error?n.message:n}`),process.exit(1)}finally{await r?.()}})};import Lr from"node:path";import V from"picocolors";import Tc from"enquirer";var{prompt:Oc}=Tc,Zo=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"pageName",message:"Page name (kebab-case):",validate:o=>o?/^[a-z][a-z0-9-]*$/.test(o)?!0:"Use lowercase letters, numbers, and hyphens only":"Page name is required"}),t.loading===void 0&&r.push({type:"confirm",name:"withLoading",message:"Generate loading.tsx?",initial:!0}),t.error===void 0&&r.push({type:"confirm",name:"withError",message:"Generate error.tsx?",initial:!0});let n=r.length>0?await Oc(r):{};return{pageName:e??n.pageName,withLoading:t.loading??n.withLoading??!0,withError:t.error??n.withError??!0}};var es=e=>{e.command("page [name]").description("Generate a new page/route").option("--dynamic <param>","Create dynamic route with parameter (e.g., id)").option("--group <name>","Route group to place the page in, e.g. app or marketing").option("--loading","Generate loading.tsx").option("--no-loading","Skip loading.tsx").option("--error","Generate error.tsx").option("--no-error","Skip error.tsx").action(async(t,r)=>{try{let n=process.cwd();l(V.cyan(`
651
+ `));for(let[a,c]of Object.entries(i.manifest.options)){let l=o?s.answers[a]:c.default,p=c.type==="boolean"?"true | false":(c.values??[]).join(" | ");m(` ${dt.bold(a.padEnd(18))} ${String(Array.isArray(l)?l.join(",")||"none":l).padEnd(10)} ${dt.dim(p)}`),c.label&&m(` ${"".padEnd(18)} ${dt.dim(c.label)}`)}m(""),m(dt.dim(o?"Change with: next-maker setup --set <option>=<value>":"Use with: next-maker init --set <option>=<value>")),m("")}catch(n){b(`${n instanceof Error?n.message:n}`),process.exit(1)}finally{await r?.()}})};import qr from"node:path";import H from"picocolors";import Wc from"enquirer";var{prompt:Kc}=Wc,as=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"pageName",message:"Page name (kebab-case):",validate:o=>o?/^[a-z][a-z0-9-]*$/.test(o)?!0:"Use lowercase letters, numbers, and hyphens only":"Page name is required"}),t.loading===void 0&&r.push({type:"confirm",name:"withLoading",message:"Generate loading.tsx?",initial:!0}),t.error===void 0&&r.push({type:"confirm",name:"withError",message:"Generate error.tsx?",initial:!0});let n=r.length>0?await Kc(r):{};return{pageName:e??n.pageName,withLoading:t.loading??n.withLoading??!0,withError:t.error??n.withError??!0}};var cs=e=>{e.command("page [name]").description("Generate a new page/route").option("--dynamic <param>","Create dynamic route with parameter (e.g., id)").option("--group <name>","Route group to place the page in, e.g. app or marketing").option("--loading","Generate loading.tsx").option("--no-loading","Skip loading.tsx").option("--error","Generate error.tsx").option("--no-error","Skip error.tsx").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(H.cyan(`
652
652
  \u{1F4C4} Page Generator
653
- `)),g.start("Detecting project setup...");let o=await T(n);g.succeed("Project setup detected"),l(V.dim(` i18n: ${o.hasI18n?"\u2713":"\u2717"}
654
- `));let s=await Zo(t,{loading:r.loading,error:r.error}),i=s.pageName;F(i,"page name"),r.dynamic&&F(r.dynamic,"dynamic param"),r.group&&F(r.group,"route group");let a=$(i),p=Lr.join(o.hasI18n?"src/app/[locale]":"src/app",r.group?`(${r.group})`:"");await ve(n,i,p)&&(x(`Page '${i}' already exists at ${p}/${i}!`),process.exit(1)),g.start("Generating page files..."),await wr({name:i,projectPath:n,hasI18n:o.hasI18n,group:r.group,dynamic:r.dynamic,withLoading:r.loading??s.withLoading,withError:r.error??s.withError}),g.succeed("Page files generated"),g.start("Registering route...");let c=r.dynamic?`/${i}/[${r.dynamic}]`:`/${i}`;await kr(n,i,c),g.succeed("Route registered"),o.hasI18n&&(g.start("Adding translation namespace..."),await Se(n,a),g.succeed("Translation namespace added"));let d=r.dynamic?Lr.join(p,i,`[${r.dynamic}]`):Lr.join(p,i);l(V.green(`
655
- \u2728 Page '${i}' created successfully!
656
- `)),l(V.dim("Generated files:")),l(V.dim(` \u{1F4C2} ${d}/`)),l(V.dim(" \u251C\u2500\u2500 page.tsx")),(r.loading??s.withLoading)&&l(V.dim(" \u251C\u2500\u2500 loading.tsx")),(r.error??s.withError)&&l(V.dim(" \u2514\u2500\u2500 error.tsx")),l(""),o.hasI18n&&(l(V.cyan("Next steps:")),l(V.dim(` 1. Add translations in: src/i18n/translations/en.json \u2192 "${a}"`)),l(V.dim(` 2. Visit: http://localhost:3000/${i}`)),l(""))}catch(n){g.fail("Page generation failed"),x(`${n}`),process.exit(1)}})};import Ur from"node:path";import ue from"picocolors";var ts=e=>{e.command("provider <name>").description("Generate a context provider in src/providers/ and wire it into RootProvider").action(async t=>{try{let r=process.cwd();l(ue.cyan(`
653
+ `)),h.start("Detecting project setup...");let s=await O(n);h.succeed("Project setup detected"),m(H.dim(` i18n: ${s.hasI18n?"\u2713":"\u2717"}
654
+ `));let i=await as(t,{loading:r.loading,error:r.error}),a=i.pageName;M(a,"page name"),r.dynamic&&M(r.dynamic,"dynamic param"),r.group&&M(r.group,"route group");let c=$(a),l=qr.join(s.hasI18n?"src/app/[locale]":"src/app",r.group?`(${r.group})`:"");await ke(n,a,l)&&(b(`Page '${a}' already exists at ${l}/${a}!`),process.exit(1)),h.start("Generating page files..."),await Pr({name:a,projectPath:n,hasI18n:s.hasI18n,group:r.group,dynamic:r.dynamic,withLoading:r.loading??i.withLoading,withError:r.error??i.withError}),h.succeed("Page files generated"),h.start("Registering route...");let u=r.dynamic?`/${a}/[${r.dynamic}]`:`/${a}`;await Cr(n,a,u),h.succeed("Route registered"),s.hasI18n&&(h.start("Adding translation namespace..."),await Te(n,c),h.succeed("Translation namespace added"));let f=r.dynamic?qr.join(l,a,`[${r.dynamic}]`):qr.join(l,a);await k(n,o),m(H.green(`
655
+ \u2728 Page '${a}' created successfully!
656
+ `)),m(H.dim("Generated files:")),m(H.dim(` \u{1F4C2} ${f}/`)),m(H.dim(" \u251C\u2500\u2500 page.tsx")),(r.loading??i.withLoading)&&m(H.dim(" \u251C\u2500\u2500 loading.tsx")),(r.error??i.withError)&&m(H.dim(" \u2514\u2500\u2500 error.tsx")),m(""),s.hasI18n&&(m(H.cyan("Next steps:")),m(H.dim(` 1. Add translations in: src/i18n/translations/en.json \u2192 "${c}"`)),m(H.dim(` 2. Visit: http://localhost:3000/${a}`)),m(""))}catch(n){h.fail("Page generation failed"),b(`${n}`),process.exit(1)}})};import Jr from"node:path";import fe from"picocolors";var ps=e=>{e.command("provider <name>").description("Generate a context provider in src/providers/ and wire it into RootProvider").action(async t=>{try{let r=process.cwd(),n=Date.now();m(fe.cyan(`
657
657
  \u{1F50C} Provider Generator
658
- `)),g.start("Generating provider...");let{componentName:n,fileBaseName:o,providerFile:s}=await br({name:t,projectPath:r});g.succeed("Provider generated"),g.start("Registering provider in RootProvider and barrel...");let{rootProviderFile:i,barrelFile:a}=await jr({projectPath:r,componentName:n,fileBaseName:o});g.succeed("Provider registered"),l(ue.green(`
659
- \u2728 ${n} created!
660
- `)),l(ue.dim("Generated files:")),l(ue.dim(` \u{1F4C4} ${Ur.relative(r,s)}`)),i?l(ue.dim(` \u270F\uFE0F ${Ur.relative(r,i)} \u2014 wrapped {children}`)):(l(ue.yellow(`
661
- \u26A0\uFE0F Could not locate a RootProvider file. Wire the new provider manually:`)),l(ue.dim(` <${n}>{children}</${n}>`))),a&&l(ue.dim(` \u270F\uFE0F ${Ur.relative(r,a)} \u2014 added re-export`)),l("")}catch(r){g.fail("Provider generation failed"),x(`${r instanceof Error?r.message:r}`),process.exit(1)}})};import Ac from"picocolors";var rs=e=>{e.command("remove <feature>").alias("uninstall").description("Turn a boolean starter feature off (shorthand for `setup --set <feature>=false`)").option("-y, --yes","Skip the confirmation prompt").option("--dry-run","Print the plan without writing").option("--no-install","Skip dependency installation after the change").action(async(t,r)=>{try{let n=["setup","--set",`${t}=false`];r.yes&&n.push("--yes"),r.dryRun&&n.push("--dry-run"),r.install===!1&&n.push("--no-install"),await e.parseAsync([process.argv[0],process.argv[1],...n])}catch(n){x(`${n instanceof Error?n.message:n}`),process.exit(1)}}).addHelpText("after",`
662
- ${Ac.dim("Example: next-maker remove ws")}
663
- `)};import Gr from"node:path";import Br from"picocolors";var ns=e=>{e.command("api [name]").alias("service").description("Generate api/{schema,keys,server,queries,actions}.ts for a resource inside a feature").option("--feature <path>","Feature directory (default: src/features/<name>)").option("--no-actions","Skip actions.ts (read-only resource)").action(async(t,r)=>{try{let n=process.cwd();if(l(Br.cyan(`
658
+ `)),h.start("Generating provider...");let{componentName:o,fileBaseName:s,providerFile:i}=await Er({name:t,projectPath:r});h.succeed("Provider generated"),h.start("Registering provider in RootProvider and barrel...");let{rootProviderFile:a,barrelFile:c}=await Nr({projectPath:r,componentName:o,fileBaseName:s});h.succeed("Provider registered"),await k(r,n),m(fe.green(`
659
+ \u2728 ${o} created!
660
+ `)),m(fe.dim("Generated files:")),m(fe.dim(` \u{1F4C4} ${Jr.relative(r,i)}`)),a?m(fe.dim(` \u270F\uFE0F ${Jr.relative(r,a)} \u2014 wrapped {children}`)):(m(fe.yellow(`
661
+ \u26A0\uFE0F Could not locate a RootProvider file. Wire the new provider manually:`)),m(fe.dim(` <${o}>{children}</${o}>`))),c&&m(fe.dim(` \u270F\uFE0F ${Jr.relative(r,c)} \u2014 added re-export`)),m("")}catch(r){h.fail("Provider generation failed"),b(`${r instanceof Error?r.message:r}`),process.exit(1)}})};import Xc from"picocolors";var ls=e=>{e.command("remove <feature>").alias("uninstall").description("Turn a boolean starter feature off (shorthand for `setup --set <feature>=false`)").option("-y, --yes","Skip the confirmation prompt").option("--dry-run","Print the plan without writing").option("--no-install","Skip dependency installation after the change").action(async(t,r)=>{try{let n=["setup","--set",`${t}=false`];r.yes&&n.push("--yes"),r.dryRun&&n.push("--dry-run"),r.install===!1&&n.push("--no-install"),await e.parseAsync([process.argv[0],process.argv[1],...n])}catch(n){b(`${n instanceof Error?n.message:n}`),process.exit(1)}}).addHelpText("after",`
662
+ ${Xc.dim("Example: next-maker remove ws")}
663
+ `)};import zr from"node:path";import Wr from"picocolors";var ms=e=>{e.command("api [name]").alias("service").description("Generate api/{schema,keys,server,queries,actions}.ts for a resource inside a feature").option("--feature <path>","Feature directory (default: src/features/<name>)").option("--no-actions","Skip actions.ts (read-only resource)").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();if(m(Wr.cyan(`
664
664
  \u{1F50C} API Layer Generator
665
- `)),!t)throw new Error("Pass the resource name, e.g. `next-maker api invoice`.");F(t,"resource name"),r.feature&&W(r.feature,"feature path");let o=await T(n);if(!o.hasQuery||!o.hasActions)throw new Error("This generator needs @tanstack/react-query and next-safe-action (starter 2.x).");let s=r.feature?te(n,r.feature):te(n,"src","features",t);if(y(Gr.join(s,"api","schema.ts")))throw new Error(`${Gr.relative(n,s)}/api already exists.`);g.start("Generating api/ files...");let i=await nt({name:t,featurePath:s,withActions:r.actions!==!1});g.succeed("api/ generated"),g.start("Registering API endpoints..."),await ct({serviceName:t,projectPath:n}),g.succeed("Endpoints registered in src/lib/config/app-apis.ts"),l(Br.green(`
666
- \u2728 ${Gr.relative(n,s)}/api ready.
667
- `));for(let a of i)l(Br.dim(` ${a}`));l("")}catch(n){g.fail("API generation failed"),x(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import Xc from"enquirer";import q from"picocolors";import{execFile as Ic}from"node:child_process";import{cp as gh,mkdir as is,readFile as Nc,rm as as,stat as hh,writeFile as Gt}from"node:fs/promises";import Q from"node:path";import{promisify as Fc}from"node:util";var Mc=Fc(Ic),_c=new Set(["pnpm-lock.yaml","package-lock.json","yarn.lock","bun.lock","bun.lockb",".env",".next-maker.json","next-env.d.ts","tsconfig.tsbuildinfo"]),Dc=e=>_c.has(e)||e.startsWith(".env.")||e.endsWith(".log"),Lc=new Set([".png",".jpg",".jpeg",".gif",".webp",".avif",".ico",".woff",".woff2",".ttf",".otf",".pdf",".zip",".gz"]),Vr=(e,t)=>Lc.has(Q.extname(e))||t.subarray(0,8e3).includes(0),qr=async e=>{try{return await Nc(e)}catch{return null}},dt=async(e,t,r)=>{r||(await is(Q.dirname(e),{recursive:!0}),await Gt(e,t))},os=async(e,t,r,n={ours:"project",base:"starter (previous)",theirs:"starter (new)"})=>{let o=Q.join(process.env.TMPDIR??"/tmp",`next-maker-merge-${process.pid}-${Math.random().toString(36).slice(2)}`);await is(o,{recursive:!0});try{await Gt(Q.join(o,"ours"),e),await Gt(Q.join(o,"base"),t),await Gt(Q.join(o,"theirs"),r);try{let{stdout:s}=await Mc("git",["merge-file","-p","-L",n.ours,"-L",n.base,"-L",n.theirs,"ours","base","theirs"],{cwd:o,maxBuffer:67108864});return{content:s,conflicts:0}}catch(s){let i=s;if(typeof i.code=="number"&&i.code>0&&i.code<128&&typeof i.stdout=="string")return{content:i.stdout,conflicts:i.code};throw i.code==="ENOENT"?new Error("git is required for merges but was not found on PATH."):s}}finally{await as(o,{recursive:!0,force:!0})}},ss=["scripts","dependencies","devDependencies","peerDependencies","optionalDependencies","engines"],Uc=(e,t,r)=>{let n=structuredClone(e),o=[],s=(a,p)=>JSON.stringify(a)===JSON.stringify(p),i=(a,p,m,c,d,u)=>{let f=m[d],h=c[d],w=p[d];if(!s(f,h)){if(s(w,f)||s(w,h)){h===void 0?delete a[d]:a[d]=h;return}o.push(u)}};for(let a of ss){let p=t[a]??{},m=r[a]??{},c=e[a]??{};n[a]||(n[a]={});let d=n[a];for(let u of new Set([...Object.keys(p),...Object.keys(m)]))i(d,c,p,m,u,`${a}.${u}`);Object.keys(d).length===0&&!(a in r)?delete n[a]:a!=="scripts"&&a!=="engines"&&(n[a]=Object.fromEntries(Object.entries(d).sort(([u],[f])=>u.localeCompare(f))))}for(let a of new Set([...Object.keys(t),...Object.keys(r)]))ss.includes(a)||i(n,e,t,r,a,a);return{result:n,conflicts:o}},Ve=async({base:e,theirs:t,ours:r},n={})=>{let o=n.dryRun??!1,s=n.skip??Dc,[i,a,p]=await Promise.all([L(e),L(t),L(r)]),m=new Set(p),c=new Set(i),d=new Set(a),u={entries:[],conflicts:[]},f=(h,w,P)=>{u.entries.push({file:h,outcome:w,note:P}),w==="conflict"&&u.conflicts.push(h)};for(let h of[...new Set([...i,...a])].sort()){if(s(h))continue;let w=c.has(h),P=d.has(h),b=m.has(h),[S,R,D]=await Promise.all([w?qr(Q.join(e,h)):null,P?qr(Q.join(t,h)):null,b?qr(Q.join(r,h)):null]),Ce=Q.join(r,h);if(P&&!w){if(!b)await dt(Ce,R,o),f(h,"added");else if(D.equals(R))f(h,"unchanged");else if(Vr(h,R))f(h,"kept","starter added a binary the project also has");else{let ut=await os(D.toString("utf8"),"",R.toString("utf8"));await dt(Ce,ut.content,o),f(h,ut.conflicts?"conflict":"merged")}continue}if(w&&!P){if(!b)continue;D.equals(S)?(o||await as(Ce,{force:!0}),f(h,"deleted")):f(h,"kept","starter removed it, but the project changed it");continue}if(!b){f(h,"kept","deleted in the project");continue}if(S.equals(R)||D.equals(R)){f(h,"unchanged");continue}if(D.equals(S)){await dt(Ce,R,o),f(h,"updated");continue}if(Vr(h,D)||Vr(h,R)){f(h,"kept","binary changed on both sides");continue}if(h==="package.json"){let{result:ut,conflicts:ft}=Uc(JSON.parse(D.toString("utf8")),JSON.parse(S.toString("utf8")),JSON.parse(R.toString("utf8")));await dt(Ce,`${JSON.stringify(ut,null,2)}
668
- `,o),f(h,ft.length?"conflict":"merged",ft.length?`project kept: ${ft.join(", ")}`:void 0),ft.length&&u.conflicts.pop();continue}let Kr=await os(D.toString("utf8"),S.toString("utf8"),R.toString("utf8"));await dt(Ce,Kr.content,o),f(h,Kr.conflicts?"conflict":"merged")}return u};import{execFile as Gc}from"node:child_process";import{mkdtemp as Bc,readFile as Vc,rm as cs}from"node:fs/promises";import{tmpdir as qc}from"node:os";import oe from"node:path";import{promisify as Jc}from"node:util";var zc=Jc(Gc),Bt=async(e,t)=>{if(t.identity)return le(t.identity.projectName,{...t.identity,copyEnv:!1});let r=JSON.parse(await Vc(oe.join(e,"package.json"),"utf-8"));return le(oe.basename(e),{projectName:r.name??oe.basename(e),description:r.description,author:typeof r.author=="string"?r.author:void 0,version:r.version,readme:y(oe.join(e,"README.md")),copyEnv:!1})},ps=e=>{let t=e.starter.source;if(t.startsWith("/")||t.startsWith(".")){if(!y(t))throw new Error(`The starter this project was generated from is a local path that no longer exists (${t}). Pass --from <ref|dir>.`);return{kind:"local",location:oe.resolve(t)}}return{kind:"remote",location:t}},Jr=e=>e.startsWith("/")||e.startsWith(".")||y(e)?{kind:"local",location:oe.resolve(e)}:B({ref:e.includes("#")?e.split("#")[1]:e,starterPath:void 0}),qe=async(e,t,r,n,o)=>{let s=await Bc(oe.join(qc(),"next-maker-ref-")),i=oe.join(s,r.projectName);try{let a=await xe({projectPath:i,source:e,supplied:t,packageManager:n});await be(i,r,a,e);let p=o?oe.join(o,"node_modules",".bin","biome"):void 0;if(p&&y(p))try{await zc(p,["check","--write","--no-errors-on-unmatched","."],{cwd:i,maxBuffer:64*1024*1024})}catch{}return{dir:i,scaffold:a,dispose:()=>cs(s,{recursive:!0,force:!0})}}catch(a){throw await cs(s,{recursive:!0,force:!0}),a}};import Wc from"enquirer";import E from"picocolors";var{prompt:Hc}=Wc,Kc={added:E.green("+"),updated:E.cyan("\u2191"),merged:E.cyan("\u21C4"),deleted:E.red("-"),conflict:E.red("\u2717"),kept:E.yellow("\xB7"),skipped:E.dim("\xB7")},zr=e=>{let t=e.entries.filter(n=>n.outcome!=="unchanged");if(t.length===0){l(E.dim(" no file changes"));return}for(let n of t)l(` ${Kc[n.outcome]??" "} ${n.outcome.padEnd(8)} ${n.file}${n.note?E.dim(` (${n.note})`):""}`);let r={};for(let n of t)r[n.outcome]=(r[n.outcome]??0)+1;if(l(""),l(E.dim(` ${Object.entries(r).map(([n,o])=>`${o} ${n}`).join(", ")}`)),e.conflicts.length){l(""),l(E.red(` ${e.conflicts.length} file(s) need attention; look for <<<<<<< markers:`));for(let n of e.conflicts)l(E.red(` ${n}`))}},ls=e=>{e.command("upgrade").description(`Merge starter changes into this project (default target: ${Pt})`).option("--to <ref|dir>","Starter tag or local checkout to upgrade to").option("--from <ref|dir>","Starter the project was generated from (default: recorded at init)").option("--starter-path <dir>","Alias for --to with a local checkout").option("-y, --yes","Skip the confirmation prompt").option("--dry-run","Report what would change without writing").option("--no-install","Skip dependency installation afterwards").action(async t=>{let r=process.cwd(),n=[];try{let o=await ee(r),s=await Bt(r,o),i=t.from?Jr(t.from):ps(o),a=t.to?Jr(t.to):B({starterPath:t.starterPath,ref:Pt});if(i.location===a.location){l(E.dim(`Already on ${a.location}; nothing to upgrade.`));return}l(E.cyan(`
665
+ `)),!t)throw new Error("Pass the resource name, e.g. `next-maker api invoice`.");M(t,"resource name"),r.feature&&W(r.feature,"feature path");let s=await O(n);if(!s.hasQuery||!s.hasActions)throw new Error("This generator needs @tanstack/react-query and next-safe-action (starter 2.x).");let i=r.feature?ne(n,r.feature):ne(n,"src","features",t);if(w(zr.join(i,"api","schema.ts")))throw new Error(`${zr.relative(n,i)}/api already exists.`);h.start("Generating api/ files...");let a=await st({name:t,featurePath:i,withActions:r.actions!==!1});h.succeed("api/ generated"),h.start("Registering API endpoints..."),await lt({serviceName:t,projectPath:n}),h.succeed("Endpoints registered in src/lib/config/app-apis.ts"),await k(n,o),m(Wr.green(`
666
+ \u2728 ${zr.relative(n,i)}/api ready.
667
+ `));for(let c of a)m(Wr.dim(` ${c}`));m("")}catch(n){h.fail("API generation failed"),b(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import wp from"enquirer";import q from"picocolors";import{execFile as op}from"node:child_process";import{cp as ey,mkdir as ws,readFile as sp,rm as xs,stat as ty,writeFile as qt}from"node:fs/promises";import ee from"node:path";import{promisify as ip}from"node:util";var Kr=(e,t)=>{let r=e.length,n=t.length;if((r+1)*(n+1)>4e6)return null;let o=n+1,s=new Int32Array((r+1)*o);for(let u=r-1;u>=0;u--)for(let f=n-1;f>=0;f--)s[u*o+f]=e[u]===t[f]?s[(u+1)*o+f+1]+1:Math.max(s[(u+1)*o+f],s[u*o+f+1]);let i=[],a=null,c=0,l=0,p=()=>(a||(a={start:c,end:c,insert:[]},i.push(a)),a);for(;c<r||l<n;){let u=c*o+l;c<r&&l<n&&e[c]===t[l]&&s[u]===s[u+o+1]+1?(a=null,c++,l++):l<n&&(c>=r||s[u+1]>=s[u+o])?(p().insert.push(t[l]),l++):p().end=++c}return i},Z=e=>e.start===e.end,Yc=(e,t)=>Z(e)&&Z(t)?!1:Z(e)?t.start<e.start&&e.start<t.end:Z(t)?e.start<t.start&&t.start<e.end:Math.max(e.start,t.start)<Math.min(e.end,t.end),Qc=(e,t)=>e.start===t.start&&e.end===t.end&&e.insert.length===t.insert.length&&e.insert.every((r,n)=>r===t.insert[n]),us=(e,t,r)=>{let n=t.start,o=t.insert;for(;n<r.end&&o.length>0&&o[0]===e[n];)o=[...o.slice(1),o[0]],n++;if(n===r.end)return{start:n,end:n,insert:o};for(n=t.start,o=t.insert;n>r.start&&o.length>0&&o[o.length-1]===e[n-1];)o=[o[o.length-1],...o.slice(0,-1)],n--;return n===r.start?{start:n,end:n,insert:o}:null},Xr=(e,t)=>e.map(r=>({start:r.start+t,end:r.end+t,insert:r.insert})),ds=(e,t,r,n)=>{let o=[],s=0,i=0,a=0,c=p=>{for(let u=s;u<p.start;u++)o.push(e[u]);o.push(...p.insert),s=Math.max(s,p.end)},l=(p,u)=>{if(!n)return!1;let f=Math.min(p.start,u.start),d=Math.max(p.end,u.end),g=i,y=a,S=!0;for(;S;){for(S=!1;g+1<t.length&&t[g+1].start<d;)g++,d=Math.max(d,t[g].end),S=!0;for(;y+1<r.length&&r[y+1].start<d;)y++,d=Math.max(d,r[y].end),S=!0}let x=n(e.slice(f,d),Xr(t.slice(i,g+1),-f),Xr(r.slice(a,y+1),-f));return x?(c({start:f,end:d,insert:x}),i=g+1,a=y+1,!0):!1};for(;i<t.length||a<r.length;){let p=t[i],u=r[a];if(p&&u){if(Qc(p,u)){c(p),i++,a++;continue}if(Yc(p,u)){let d=Z(p)&&!Z(u)?us(e,p,u):Z(u)&&!Z(p)?us(e,u,p):null;if(d&&Z(p))p=d;else if(d)u=d;else{if(l(p,u))continue;return null}}p.start<u.start||p.start===u.start&&Z(p)?(c(p),i++):(c(u),a++)}else p?(c(p),i++):u&&(c(u),a++)}for(let p=s;p<e.length;p++)o.push(e[p]);return o},Zc=(e,t,r,n)=>{let o=Kr(e,t),s=Kr(e,r);return o&&s?ds(e,o,s,n):null},ep=/\s+|[\p{L}\p{N}_$]+\s*|[^\s\p{L}\p{N}_$]\s*/gu,fs=e=>e.match(ep)??[],tp=e=>e.flatMap(t=>fs(`${t}
668
+ `)),ft=e=>{if(e==="")return[];let t=e.split(`
669
+ `);return t[t.length-1]===""&&t.pop(),t},Ht=e=>e.length?`${e.join(`
670
+ `)}
671
+ `:"",rp=(e,t,r)=>{let n=[],o=[];for(let l of e)o.push(n.length),n.push(...fs(`${l}
672
+ `));o.push(n.length);let s=l=>{let p=[];for(let u of l){let f=o[u.start],d=Kr(n.slice(f,o[u.end]),tp(u.insert));if(!d)return null;p.push(...Xr(d,f))}return p},i=s(t),a=s(r);if(!i||!a)return null;let c=ds(n,i,a);return c?ft(c.join("")):null},np=(e,t,r)=>{let n=Zc(ft(t),ft(e),ft(r),rp);return n?Ht(n):null},gs=(e,t)=>{let r=e.split(`
673
+ `),n=e.endsWith(`
674
+ `);n&&r.pop();let o=[],s=0,i=0;for(;i<r.length;){let a=r[i];if(!a.startsWith("<<<<<<< ")){o.push(a),i++;continue}let c=[],l=[],p=[],u=c;i++;let f=!1;for(;i<r.length;){let g=r[i++];if(u===c&&g.startsWith("||||||| "))u=l;else if((u===c||u===l)&&g==="=======")u=p;else if(u===p&&g.startsWith(">>>>>>> ")){f=!0;break}else u.push(g)}if(!f)throw new Error("Malformed conflict block in merge output.");let d=np(Ht(c),Ht(l),Ht(p));if(d!==null){o.push(...ft(d));continue}s++,o.push(`<<<<<<< ${t.ours}`,...c,"=======",...p,`>>>>>>> ${t.theirs}`)}return{content:o.join(`
675
+ `)+(n?`
676
+ `:""),conflicts:s}};var ap=ip(op),cp=new Set(["pnpm-lock.yaml","package-lock.json","yarn.lock","bun.lock","bun.lockb",".env",".next-maker.json","next-env.d.ts","tsconfig.tsbuildinfo"]),pp=e=>cp.has(e)||e.startsWith(".env.")||e.endsWith(".log"),lp=new Set([".png",".jpg",".jpeg",".gif",".webp",".avif",".ico",".woff",".woff2",".ttf",".otf",".pdf",".zip",".gz"]),Yr=(e,t)=>lp.has(ee.extname(e))||t.subarray(0,8e3).includes(0),Qr=async e=>{try{return await sp(e)}catch{return null}},gt=async(e,t,r)=>{r||(await ws(ee.dirname(e),{recursive:!0}),await qt(e,t))},hs=async(e,t,r,n={ours:"project",base:"starter (previous)",theirs:"starter (new)"})=>{let o=ee.join(process.env.TMPDIR??"/tmp",`next-maker-merge-${process.pid}-${Math.random().toString(36).slice(2)}`);await ws(o,{recursive:!0});try{await qt(ee.join(o,"ours"),e),await qt(ee.join(o,"base"),t),await qt(ee.join(o,"theirs"),r);try{let{stdout:s}=await ap("git",["merge-file","-p","--diff3","-L",n.ours,"-L",n.base,"-L",n.theirs,"ours","base","theirs"],{cwd:o,maxBuffer:67108864});return{content:s,conflicts:0}}catch(s){let i=s;if(typeof i.code=="number"&&i.code>0&&i.code<128&&typeof i.stdout=="string")return gs(i.stdout,n);throw i.code==="ENOENT"?new Error("git is required for merges but was not found on PATH."):s}}finally{await xs(o,{recursive:!0,force:!0})}},ys=["scripts","dependencies","devDependencies","peerDependencies","optionalDependencies","engines"],mp=(e,t,r)=>{let n=structuredClone(e),o=[],s=(a,c)=>JSON.stringify(a)===JSON.stringify(c),i=(a,c,l,p,u,f)=>{let d=l[u],g=p[u],y=c[u];if(!s(d,g)){if(s(y,d)||s(y,g)){g===void 0?delete a[u]:a[u]=g;return}o.push(f)}};for(let a of ys){let c=t[a]??{},l=r[a]??{},p=e[a]??{};n[a]||(n[a]={});let u=n[a];for(let f of new Set([...Object.keys(c),...Object.keys(l)]))i(u,p,c,l,f,`${a}.${f}`);Object.keys(u).length===0&&!(a in r)?delete n[a]:a!=="scripts"&&a!=="engines"&&(n[a]=Object.fromEntries(Object.entries(u).sort(([f],[d])=>f.localeCompare(d))))}for(let a of new Set([...Object.keys(t),...Object.keys(r)]))ys.includes(a)||i(n,e,t,r,a,a);return{result:n,conflicts:o}},qe=async({base:e,theirs:t,ours:r},n={})=>{let o=n.dryRun??!1,s=n.skip??pp,[i,a,c]=await Promise.all([L(e),L(t),L(r)]),l=new Set(c),p=new Set(i),u=new Set(a),f={entries:[],conflicts:[]},d=(g,y,S)=>{f.entries.push({file:g,outcome:y,note:S}),y==="conflict"&&f.conflicts.push(g)};for(let g of[...new Set([...i,...a])].sort()){if(s(g))continue;let y=p.has(g),S=u.has(g),x=l.has(g),[E,R,U]=await Promise.all([y?Qr(ee.join(e,g)):null,S?Qr(ee.join(t,g)):null,x?Qr(ee.join(r,g)):null]),Oe=ee.join(r,g);if(S&&!y){if(!x)await gt(Oe,R,o),d(g,"added");else if(U.equals(R))d(g,"unchanged");else if(Yr(g,R))d(g,"kept","starter added a binary the project also has");else{let ht=await hs(U.toString("utf8"),"",R.toString("utf8"));await gt(Oe,ht.content,o),d(g,ht.conflicts?"conflict":"merged")}continue}if(y&&!S){if(!x)continue;U.equals(E)?(o||await xs(Oe,{force:!0}),d(g,"deleted")):d(g,"kept","starter removed it, but the project changed it");continue}if(!x){d(g,"kept","deleted in the project");continue}if(E.equals(R)||U.equals(R)){d(g,"unchanged");continue}if(U.equals(E)){await gt(Oe,R,o),d(g,"updated");continue}if(Yr(g,U)||Yr(g,R)){d(g,"kept","binary changed on both sides");continue}if(g==="package.json"){let{result:ht,conflicts:yt}=mp(JSON.parse(U.toString("utf8")),JSON.parse(E.toString("utf8")),JSON.parse(R.toString("utf8")));await gt(Oe,`${JSON.stringify(ht,null,2)}
677
+ `,o),d(g,yt.length?"conflict":"merged",yt.length?`project kept: ${yt.join(", ")}`:void 0),yt.length&&f.conflicts.pop();continue}let nn=await hs(U.toString("utf8"),E.toString("utf8"),R.toString("utf8"));await gt(Oe,nn.content,o),d(g,nn.conflicts?"conflict":"merged")}return f};import{mkdtemp as up,readFile as dp,rm as bs}from"node:fs/promises";import{tmpdir as fp}from"node:os";import ge from"node:path";var Jt=async(e,t)=>{if(t.identity)return me(t.identity.projectName,{...t.identity,copyEnv:!1});let r=JSON.parse(await dp(ge.join(e,"package.json"),"utf-8"));return me(ge.basename(e),{projectName:r.name??ge.basename(e),description:r.description,author:typeof r.author=="string"?r.author:void 0,version:r.version,readme:w(ge.join(e,"README.md")),copyEnv:!1})},vs=e=>{let t=e.starter.source;if(t.startsWith("/")||t.startsWith(".")){if(!w(t))throw new Error(`The starter this project was generated from is a local path that no longer exists (${t}). Pass --from <ref|dir>.`);return{kind:"local",location:ge.resolve(t)}}return{kind:"remote",location:t}},Zr=e=>e.startsWith("/")||e.startsWith(".")||w(e)?{kind:"local",location:ge.resolve(e)}:V({ref:e.includes("#")?e.split("#")[1]:e,starterPath:void 0}),Je=async(e,t,r,n,o)=>{let s=await up(ge.join(fp(),"next-maker-ref-")),i=ge.join(s,r.projectName);try{let a=await ve({projectPath:i,source:e,supplied:t,packageManager:n});return await $e(i,r,a,e),o&&await pr(i,["."],o),{dir:i,scaffold:a,dispose:()=>bs(s,{recursive:!0,force:!0})}}catch(a){throw await bs(s,{recursive:!0,force:!0}),a}};import gp from"enquirer";import T from"picocolors";var{prompt:hp}=gp,yp={added:T.green("+"),updated:T.cyan("\u2191"),merged:T.cyan("\u21C4"),deleted:T.red("-"),conflict:T.red("\u2717"),kept:T.yellow("\xB7"),skipped:T.dim("\xB7")},en=e=>{let t=e.entries.filter(n=>n.outcome!=="unchanged");if(t.length===0){m(T.dim(" no file changes"));return}for(let n of t)m(` ${yp[n.outcome]??" "} ${n.outcome.padEnd(8)} ${n.file}${n.note?T.dim(` (${n.note})`):""}`);let r={};for(let n of t)r[n.outcome]=(r[n.outcome]??0)+1;if(m(""),m(T.dim(` ${Object.entries(r).map(([n,o])=>`${o} ${n}`).join(", ")}`)),e.conflicts.length){m(""),m(T.red(` ${e.conflicts.length} file(s) need attention; look for <<<<<<< markers:`));for(let n of e.conflicts)m(T.red(` ${n}`))}},$s=e=>{e.command("upgrade").description(`Merge starter changes into this project (default target: ${Et})`).option("--to <ref|dir>","Starter tag or local checkout to upgrade to").option("--from <ref|dir>","Starter the project was generated from (default: recorded at init)").option("--starter-path <dir>","Alias for --to with a local checkout").option("-y, --yes","Skip the confirmation prompt").option("--dry-run","Report what would change without writing").option("--no-install","Skip dependency installation afterwards").action(async t=>{let r=process.cwd(),n=[];try{let o=await re(r),s=await Jt(r,o),i=t.from?Zr(t.from):vs(o),a=t.to?Zr(t.to):V({starterPath:t.starterPath,ref:Et});if(i.location===a.location){m(T.dim(`Already on ${a.location}; nothing to upgrade.`));return}m(T.cyan(`
669
678
  \u2B06 Upgrade
670
- `)),l(` ${E.dim("from")} ${i.location}`),l(` ${E.dim("to ")} ${a.location}
671
- `);let p=await qe(i,o.answers,s,o.packageManager,r);n.push(p.dispose);let m=await qe(a,o.answers,s,o.packageManager,r);n.push(m.dispose);for(let u of m.scaffold.forced)l(E.yellow(` ! ${u.reason}; ${u.option} turned off`));for(let u of m.scaffold.unknown)l(E.yellow(` ! option "${u}" no longer exists in the new starter`));let c=await Ve({base:p.dir,theirs:m.dir,ours:r},{dryRun:!0});if(zr(c),t.dryRun){l(E.dim(`
679
+ `)),m(` ${T.dim("from")} ${i.location}`),m(` ${T.dim("to ")} ${a.location}
680
+ `);let c=await Je(i,o.answers,s,o.packageManager,r);n.push(c.dispose);let l=await Je(a,o.answers,s,o.packageManager,r);n.push(l.dispose);for(let d of l.scaffold.forced)m(T.yellow(` ! ${d.reason}; ${d.option} turned off`));for(let d of l.scaffold.unknown)m(T.yellow(` ! option "${d}" no longer exists in the new starter`));let p=await qe({base:c.dir,theirs:l.dir,ours:r},{dryRun:!0});if(en(p),t.dryRun){m(T.dim(`
672
681
  Dry run: nothing was written.
673
- `));return}if(!t.yes){let{confirm:u}=await Hc({type:"confirm",name:"confirm",message:"Apply these changes?",initial:!1});if(!u){l(E.yellow(`Aborted.
674
- `));return}}let d=await Ve({base:p.dir,theirs:m.dir,ours:r});await me(r,{...o,cli:Te.version,starter:{...m.scaffold.manifest.starter,source:a.location},answers:m.scaffold.answers,identity:o.identity??{projectName:s.projectName,description:s.description,author:s.author,version:s.version,email:s.email,gitRemote:s.gitRemote,readme:s.readme}}),t.install!==!1&&(l(E.dim(`
675
- Installing with ${o.packageManager}...`)),await pe(r,o.packageManager)),l(E.green(`
676
- \u2713 Upgraded to ${m.scaffold.manifest.starter.version}.`)),d.conflicts.length?l(E.yellow(" Resolve the conflicts above, then run `next-maker doctor --compile`.")):l(E.dim(" Run `next-maker doctor --compile` to confirm.")),l("")}catch(o){x(`${o instanceof Error?o.message:o}`),process.exit(1)}finally{for(let o of n)await o()}})};var{prompt:Yc}=Xc,Qc=(e,t=[])=>[...t,e],ms=e=>{e.command("setup").description("Turn starter features on or off in an existing project (e.g. --set ws=true)").option("--set <key=value>","Option to change (repeatable), e.g. --set i18n=false --set state=zustand",Qc).option("-y, --yes","Skip the confirmation prompt").option("--dry-run","Print the plan without writing").option("--no-install","Skip dependency installation after the change").option("--starter-path <dir>","Use a local starter checkout").action(async t=>{let r=process.cwd(),n=[];try{let o=await ee(r),s=ye(t.set);if(Object.keys(s).length===0)throw new Error("Nothing to change. Pass at least one --set key=value (run `next-maker options` to list them).");let i=await Me(o,{starterPath:t.starterPath});n.push(i.dispose);let{answers:a,forced:p,unknown:m}=Ke(i.manifest,{...o.answers,...s});for(let P of m)l(q.yellow(` ! unknown option "${P}" ignored`));for(let P of p)l(q.yellow(` ! ${P.reason}; ${P.option} turned off`));let c=Object.keys(a).filter(P=>JSON.stringify(a[P])!==JSON.stringify(o.answers[P]));if(l(q.cyan(`
682
+ `));return}if(!t.yes){let{confirm:d}=await hp({type:"confirm",name:"confirm",message:"Apply these changes?",initial:!1});if(!d){m(T.yellow(`Aborted.
683
+ `));return}}let u=Date.now(),f=await qe({base:c.dir,theirs:l.dir,ours:r});await k(r,u),await ue(r,{...o,cli:Ae.version,starter:{...l.scaffold.manifest.starter,source:a.location},answers:l.scaffold.answers,identity:o.identity??{projectName:s.projectName,description:s.description,author:s.author,version:s.version,email:s.email,gitRemote:s.gitRemote,readme:s.readme}}),t.install!==!1&&(m(T.dim(`
684
+ Installing with ${o.packageManager}...`)),await le(r,o.packageManager)),m(T.green(`
685
+ \u2713 Upgraded to ${l.scaffold.manifest.starter.version}.`)),f.conflicts.length?m(T.yellow(" Resolve the conflicts above, then run `next-maker doctor --compile`.")):m(T.dim(" Run `next-maker doctor --compile` to confirm.")),m("")}catch(o){b(`${o instanceof Error?o.message:o}`),process.exit(1)}finally{for(let o of n)await o()}})};var{prompt:xp}=wp,bp=(e,t=[])=>[...t,e],ks=e=>{e.command("setup").description("Turn starter features on or off in an existing project (e.g. --set ws=true)").option("--set <key=value>","Option to change (repeatable), e.g. --set i18n=false --set state=zustand",bp).option("-y, --yes","Skip the confirmation prompt").option("--dry-run","Print the plan without writing").option("--no-install","Skip dependency installation after the change").option("--starter-path <dir>","Use a local starter checkout").action(async t=>{let r=process.cwd(),n=[];try{let o=await re(r),s=xe(t.set);if(Object.keys(s).length===0)throw new Error("Nothing to change. Pass at least one --set key=value (run `next-maker options` to list them).");let i=await De(o,{starterPath:t.starterPath});n.push(i.dispose);let{answers:a,forced:c,unknown:l}=Ye(i.manifest,{...o.answers,...s});for(let x of l)m(q.yellow(` ! unknown option "${x}" ignored`));for(let x of c)m(q.yellow(` ! ${x.reason}; ${x.option} turned off`));let p=Object.keys(a).filter(x=>JSON.stringify(a[x])!==JSON.stringify(o.answers[x]));if(m(q.cyan(`
677
686
  \u{1F527} Setup
678
- `)),c.length===0){l(q.dim(`No option changes; the project already has these values.
679
- `));return}for(let P of c)l(` ${q.dim(P.padEnd(18))} ${String(o.answers[P])} ${q.dim("\u2192")} ${String(a[P])}`);l("");let d=await Bt(r,o),u=await qe(i.source,o.answers,d,o.packageManager,r);n.push(u.dispose);let f=await qe(i.source,a,d,o.packageManager,r);n.push(f.dispose);let h=await Ve({base:u.dir,theirs:f.dir,ours:r},{dryRun:!0});if(zr(h),t.dryRun){l(q.dim(`
687
+ `)),p.length===0){m(q.dim(`No option changes; the project already has these values.
688
+ `));return}for(let x of p)m(` ${q.dim(x.padEnd(18))} ${String(o.answers[x])} ${q.dim("\u2192")} ${String(a[x])}`);m("");let u=await Jt(r,o),f=await Je(i.source,o.answers,u,o.packageManager,r);n.push(f.dispose);let d=await Je(i.source,a,u,o.packageManager,r);n.push(d.dispose);let g=await qe({base:f.dir,theirs:d.dir,ours:r},{dryRun:!0});if(en(g),t.dryRun){m(q.dim(`
680
689
  Dry run: nothing was written.
681
- `));return}if(!t.yes){let{confirm:P}=await Yc({type:"confirm",name:"confirm",message:"Apply these changes?",initial:!1});if(!P){l(q.yellow(`Aborted.
682
- `));return}}let w=await Ve({base:u.dir,theirs:f.dir,ours:r});await me(r,{...o,answers:a}),t.install!==!1&&(l(q.dim(`
683
- Installing with ${o.packageManager}...`)),await pe(r,o.packageManager)),l(q.green(`
684
- \u2713 Applied.`)),w.conflicts.length&&l(q.yellow(" Resolve the conflicts above, then run `next-maker doctor --compile`.")),l("")}catch(o){x(`${o instanceof Error?o.message:o}`),process.exit(1)}finally{for(let o of n)await o()}})};import Wr from"node:path";import Vt from"picocolors";import Zc from"enquirer";var{prompt:ep}=Zc,ds=async(e,t)=>{let r=[];e||r.push({type:"input",name:"sliceName",message:"What is the slice name?",initial:"my-slice",validate:o=>/^[a-z0-9-]+$/.test(o)?!0:"Slice name must be lowercase and contain only alphanumeric characters and hyphens."}),t===void 0&&r.push({type:"confirm",name:"persistSlice",message:"Enable persistence for this slice?",initial:!1});let n=r.length>0?await ep(r):{};return{sliceName:e||n.sliceName,persistSlice:t===void 0?n.persistSlice||!1:t}};var us=e=>{e.command("slice [name]").description("Generate a store slice (Redux or Zustand, whichever the project uses)").option("--path <path>","Directory for the slice (default: src/store/slices/<name>)").option("--persist","Persist the slice across reloads (Redux)").option("--no-persist","Do not persist the slice").option("--test","Also generate a sibling test file (Redux)").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd();l(Vt.cyan(`
690
+ `));return}if(!t.yes){let{confirm:x}=await xp({type:"confirm",name:"confirm",message:"Apply these changes?",initial:!1});if(!x){m(q.yellow(`Aborted.
691
+ `));return}}let y=Date.now(),S=await qe({base:f.dir,theirs:d.dir,ours:r});await k(r,y),await ue(r,{...o,answers:a}),t.install!==!1&&(m(q.dim(`
692
+ Installing with ${o.packageManager}...`)),await le(r,o.packageManager)),m(q.green(`
693
+ \u2713 Applied.`)),S.conflicts.length&&m(q.yellow(" Resolve the conflicts above, then run `next-maker doctor --compile`.")),m("")}catch(o){b(`${o instanceof Error?o.message:o}`),process.exit(1)}finally{for(let o of n)await o()}})};import tn from"node:path";import zt from"picocolors";import vp from"enquirer";var{prompt:$p}=vp,Ps=async(e,t)=>{let r=[];e||r.push({type:"input",name:"sliceName",message:"What is the slice name?",initial:"my-slice",validate:o=>/^[a-z0-9-]+$/.test(o)?!0:"Slice name must be lowercase and contain only alphanumeric characters and hyphens."}),t===void 0&&r.push({type:"confirm",name:"persistSlice",message:"Enable persistence for this slice?",initial:!1});let n=r.length>0?await $p(r):{};return{sliceName:e||n.sliceName,persistSlice:t===void 0?n.persistSlice||!1:t}};var Ss=e=>{e.command("slice [name]").description("Generate a store slice (Redux or Zustand, whichever the project uses)").option("--path <path>","Directory for the slice (default: src/store/slices/<name>)").option("--persist","Persist the slice across reloads (Redux)").option("--no-persist","Do not persist the slice").option("--test","Also generate a sibling test file (Redux)").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(zt.cyan(`
685
694
  \u{1F527} Slice Generator
686
- `)),g.start("Detecting project setup...");let o=await T(n);if(g.succeed("Project setup detected"),o.state==="none")throw new Error("This project has no client store. Re-run init with a state store, or add one with `next-maker setup --set state=redux`.");l(Vt.dim(` state: ${o.state}
687
- `));let s=await ds(t,o.state==="zustand"?!1:r.persist);F(s.sliceName,"slice name"),r.path&&W(r.path,"path");let i=r.path??Wr.join("src","store","slices"),a=te(n,i,s.sliceName);if(await ve(n,s.sliceName,i))throw new Error(`Slice '${s.sliceName}' already exists at ${i}.`);g.start("Generating slice files..."),await ot({name:s.sliceName,outputPath:a,persist:s.persistSlice,state:o.state}),g.succeed("Slice files generated"),o.state==="redux"&&(g.start("Registering slice in the store..."),await pt({projectPath:n,name:s.sliceName,persist:s.persistSlice,importPath:Wr.join(i,s.sliceName)}),g.succeed("Slice registered"),(r.test??o.hasTests)&&(g.start("Generating test..."),await re({projectPath:n,sourceFile:Wr.join(a,`${s.sliceName}.slice.ts`),kind:"slice",symbolName:s.sliceName.replace(/-([a-z])/g,(p,m)=>m.toUpperCase())}),g.succeed("Test generated"))),l(Vt.green(`
688
- \u2728 Slice '${s.sliceName}' created in ${i}/${s.sliceName}/.
689
- `)),o.state==="zustand"&&(l(Vt.yellow(` ! Compose create${$(s.sliceName)}Slice into AppState in src/store/index.ts`)),l(""))}catch(n){g.fail("Slice generation failed"),x(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import J from"node:path";import Hr from"picocolors";var fs=e=>{e.command("test <file>").description(`Generate a sibling test file for an existing component, hook, or slice.
690
- Infers the kind from filename/content; pass --kind to override.`).option("--kind <kind>","Override inferred kind: component | hook | slice").option("--force","Overwrite an existing test file").action(async(t,r)=>{try{let n=process.cwd(),o=J.isAbsolute(t)?t:J.join(n,t);l(Hr.cyan(`
695
+ `)),h.start("Detecting project setup...");let s=await O(n);if(h.succeed("Project setup detected"),s.state==="none")throw new Error("This project has no client store. Re-run init with a state store, or add one with `next-maker setup --set state=redux`.");m(zt.dim(` state: ${s.state}
696
+ `));let i=await Ps(t,s.state==="zustand"?!1:r.persist);M(i.sliceName,"slice name"),r.path&&W(r.path,"path");let a=r.path??tn.join("src","store","slices"),c=ne(n,a,i.sliceName);if(await ke(n,i.sliceName,a))throw new Error(`Slice '${i.sliceName}' already exists at ${a}.`);h.start("Generating slice files..."),await it({name:i.sliceName,outputPath:c,persist:i.persistSlice,state:s.state}),h.succeed("Slice files generated"),s.state==="redux"&&(h.start("Registering slice in the store..."),await mt({projectPath:n,name:i.sliceName,persist:i.persistSlice,importPath:tn.join(a,i.sliceName)}),h.succeed("Slice registered"),(r.test??s.hasTests)&&(h.start("Generating test..."),await oe({projectPath:n,sourceFile:tn.join(c,`${i.sliceName}.slice.ts`),kind:"slice",symbolName:i.sliceName.replace(/-([a-z])/g,(l,p)=>p.toUpperCase())}),h.succeed("Test generated"))),await k(n,o),m(zt.green(`
697
+ \u2728 Slice '${i.sliceName}' created in ${a}/${i.sliceName}/.
698
+ `)),s.state==="zustand"&&(m(zt.yellow(` ! Compose create${$(i.sliceName)}Slice into AppState in src/store/index.ts`)),m(""))}catch(n){h.fail("Slice generation failed"),b(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import J from"node:path";import rn from"picocolors";var Es=e=>{e.command("test <file>").description(`Generate a sibling test file for an existing component, hook, or slice.
699
+ Infers the kind from filename/content; pass --kind to override.`).option("--kind <kind>","Override inferred kind: component | hook | slice").option("--force","Overwrite an existing test file").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now(),s=J.isAbsolute(t)?t:J.join(n,t);m(rn.cyan(`
691
700
  \u{1F9EA} Test Generator
692
- `)),y(o)||(x(`Source file not found: ${t}`),process.exit(1));let s=await T(n);s.hasTests||(x("Testing is not installed in this project. Run `next-maker setup --tests` first."),process.exit(1));let i=await j(o),a=tp(r.kind)??rp(o,i);a||(x(`Could not infer test kind for ${J.basename(o)}. Pass --kind component|hook|slice.`),process.exit(1));let p=np(o,a),m=op(o,a);y(m)&&!r.force&&(x(`Test file already exists: ${J.relative(n,m)}. Use --force to overwrite.`),process.exit(1)),g.start(`Generating ${a} test...`);let c=await re({projectPath:n,sourceFile:o,kind:a,symbolName:p,hasState:s.state!=="none",hasI18n:s.hasI18n,hookUsesStore:a==="hook"&&s.state!=="none"&&i.includes("useAppSelector")});g.succeed("Test generated"),l(Hr.green(`
693
- \u2728 Test '${J.basename(c)}' created.
694
- `)),l(Hr.dim(` \u{1F9EA} ${J.relative(n,c)}`)),l("")}catch(n){g.fail("Test generation failed"),x(`${n}`),process.exit(1)}})},tp=e=>{if(!e)return null;if(e==="component"||e==="hook"||e==="slice")return e;throw new Error(`Invalid --kind: ${e}. Use component | hook | slice.`)},rp=(e,t)=>{let r=J.basename(e);return/\.slice\.ts$/.test(r)?"slice":/^use[A-Z]/.test(r.replace(/\.tsx?$/,""))?"hook":r.endsWith(".tsx")?"component":/createSlice\s*\(/.test(t)?"slice":/^export\s+(const|function)\s+use[A-Z]/m.test(t)?"hook":null},np=(e,t)=>{let r=J.basename(e).replace(/\.(tsx?|jsx?)$/i,"");return t==="slice"?U(r.replace(/\.slice$/,"")):t==="hook"?/^use[A-Z]/.test(r)?r:`use${$(r.replace(/^use-?/,""))}`:$(r)},op=(e,t)=>{let r=J.dirname(e),n=J.basename(e).replace(/\.(tsx?|jsx?)$/i,""),o=t==="component"?".tsx":".ts";return J.join(r,`${n}.test${o}`)};import{chmod as sp,cp as ip,mkdir as qt,readFile as Jt,rm as ap,writeFile as I}from"node:fs/promises";import v from"node:path";import fe from"picocolors";var gs=e=>{let t={"@biomejs/biome":e.biomeVersion,turbo:e.turboVersion};e.hooks&&(e.huskyVersion&&(t.husky=e.huskyVersion),e.lintStagedVersion&&(t["lint-staged"]=e.lintStagedVersion),e.commitlintCliVersion&&(t["@commitlint/cli"]=e.commitlintCliVersion),e.commitlintConfigVersion&&(t["@commitlint/config-conventional"]=e.commitlintConfigVersion));let r={name:e.name,version:"0.1.0",description:e.description,author:e.author,private:!0,type:"module",packageManager:e.packageManagerPin,engines:{node:e.nodeEngine,pnpm:">=11.0.0"},scripts:{dev:"turbo run dev",build:"turbo run build",start:"turbo run start",lint:"turbo run lint","lint:fix":"biome check --write . && turbo run lint:fix","ci:check":"biome ci . && turbo run ci:check","type-check":"turbo run type-check","check:deprecated":"turbo run check:deprecated",test:"turbo run test","test:e2e":"turbo run test:e2e",validate:"pnpm ci:check && pnpm type-check && pnpm check:deprecated && pnpm test && pnpm build",...e.hooks?{prepare:"husky","lint-staged":"lint-staged"}:{}},devDependencies:Object.fromEntries(Object.entries(t).sort())};return`${JSON.stringify(r,null,2)}
695
- `},hs=e=>`packages:
701
+ `)),w(s)||(b(`Source file not found: ${t}`),process.exit(1));let i=await O(n);i.hasTests||(b("Testing is not installed in this project. Run `next-maker setup --tests` first."),process.exit(1));let a=await j(s),c=kp(r.kind)??Pp(s,a);c||(b(`Could not infer test kind for ${J.basename(s)}. Pass --kind component|hook|slice.`),process.exit(1));let l=Sp(s,c),p=Ep(s,c);w(p)&&!r.force&&(b(`Test file already exists: ${J.relative(n,p)}. Use --force to overwrite.`),process.exit(1)),h.start(`Generating ${c} test...`);let u=await oe({projectPath:n,sourceFile:s,kind:c,symbolName:l,hasState:i.state!=="none",hasI18n:i.hasI18n,hookUsesStore:c==="hook"&&i.state!=="none"&&a.includes("useAppSelector")});h.succeed("Test generated"),await k(n,o),m(rn.green(`
702
+ \u2728 Test '${J.basename(u)}' created.
703
+ `)),m(rn.dim(` \u{1F9EA} ${J.relative(n,u)}`)),m("")}catch(n){h.fail("Test generation failed"),b(`${n}`),process.exit(1)}})},kp=e=>{if(!e)return null;if(e==="component"||e==="hook"||e==="slice")return e;throw new Error(`Invalid --kind: ${e}. Use component | hook | slice.`)},Pp=(e,t)=>{let r=J.basename(e);return/\.slice\.ts$/.test(r)?"slice":/^use[A-Z]/.test(r.replace(/\.tsx?$/,""))?"hook":r.endsWith(".tsx")?"component":/createSlice\s*\(/.test(t)?"slice":/^export\s+(const|function)\s+use[A-Z]/m.test(t)?"hook":null},Sp=(e,t)=>{let r=J.basename(e).replace(/\.(tsx?|jsx?)$/i,"");return t==="slice"?G(r.replace(/\.slice$/,"")):t==="hook"?/^use[A-Z]/.test(r)?r:`use${$(r.replace(/^use-?/,""))}`:$(r)},Ep=(e,t)=>{let r=J.dirname(e),n=J.basename(e).replace(/\.(tsx?|jsx?)$/i,""),o=t==="component"?".tsx":".ts";return J.join(r,`${n}.test${o}`)};import{chmod as Tp,cp as Rp,mkdir as Wt,readFile as Kt,rm as jp,writeFile as N}from"node:fs/promises";import v from"node:path";import he from"picocolors";var Ts=e=>{let t={"@biomejs/biome":e.biomeVersion,turbo:e.turboVersion};e.hooks&&(e.huskyVersion&&(t.husky=e.huskyVersion),e.lintStagedVersion&&(t["lint-staged"]=e.lintStagedVersion),e.commitlintCliVersion&&(t["@commitlint/cli"]=e.commitlintCliVersion),e.commitlintConfigVersion&&(t["@commitlint/config-conventional"]=e.commitlintConfigVersion));let r={name:e.name,version:"0.1.0",description:e.description,author:e.author,private:!0,type:"module",packageManager:e.packageManagerPin,engines:{node:e.nodeEngine,pnpm:">=11.0.0"},scripts:{dev:"turbo run dev",build:"turbo run build",start:"turbo run start",lint:"turbo run lint","lint:fix":"biome check --write . && turbo run lint:fix","ci:check":"biome ci . && turbo run ci:check","type-check":"turbo run type-check","check:deprecated":"turbo run check:deprecated",test:"turbo run test","test:e2e":"turbo run test:e2e",validate:"pnpm ci:check && pnpm type-check && pnpm check:deprecated && pnpm test && pnpm build",...e.hooks?{prepare:"husky","lint-staged":"lint-staged"}:{}},devDependencies:Object.fromEntries(Object.entries(t).sort())};return`${JSON.stringify(r,null,2)}
704
+ `},Rs=e=>`packages:
696
705
  - 'apps/*'
697
706
  - 'packages/*'
698
707
 
699
708
  ${e.split(`
700
709
  `).filter(r=>!r.startsWith("packages:")&&!r.startsWith("# Single-package")&&!r.startsWith("# Monorepo mode")).join(`
701
710
  `).trim()}
702
- `,ys=()=>`${JSON.stringify({$schema:"https://turborepo.com/schema.json",ui:"tui",globalEnv:["NODE_ENV","CI"],globalPassThroughEnv:["NEXT_PUBLIC_*","API_INTERNAL_URL","CSP_MODE","BUILD_STANDALONE","DEFAULT_TIMEZONE","DEFAULT_LOCALE","NEXT_TELEMETRY_DISABLED"],tasks:{build:{dependsOn:["^build"],inputs:["$TURBO_DEFAULT$",".env.production",".env"],outputs:[".next/**","!.next/cache/**"]},dev:{cache:!1,persistent:!0},start:{cache:!1,persistent:!0,dependsOn:["build"]},lint:{},"lint:fix":{cache:!1},"ci:check":{},"type-check":{dependsOn:["^build"]},"check:deprecated":{dependsOn:["^build"]},test:{dependsOn:["^build"],outputs:["coverage/**"]},"test:e2e":{dependsOn:["build"],cache:!1}}},null,2)}
703
- `,ws=e=>`${JSON.stringify({$schema:`https://biomejs.dev/schemas/${e.replace(/^[\^~]/,"")}/schema.json`,vcs:{enabled:!0,clientKind:"git",useIgnoreFile:!0},files:{includes:["*.json","*.mjs","*.ts",".github/**","!apps","!packages"]},formatter:{enabled:!0,indentStyle:"space",indentWidth:2,lineWidth:100,lineEnding:"lf"},javascript:{formatter:{quoteStyle:"single",semicolons:"always",trailingCommas:"all"}},json:{formatter:{trailingCommas:"none"}},linter:{enabled:!0,rules:{preset:"recommended"}}},null,2)}
704
- `,xs=()=>`# dependencies
711
+ `,js=()=>`${JSON.stringify({$schema:"https://turborepo.com/schema.json",ui:"tui",globalEnv:["NODE_ENV","CI"],globalPassThroughEnv:["NEXT_PUBLIC_*","API_INTERNAL_URL","CSP_MODE","BUILD_STANDALONE","DEFAULT_TIMEZONE","DEFAULT_LOCALE","NEXT_TELEMETRY_DISABLED"],tasks:{build:{dependsOn:["^build"],inputs:["$TURBO_DEFAULT$",".env.production",".env"],outputs:[".next/**","!.next/cache/**"]},dev:{cache:!1,persistent:!0},start:{cache:!1,persistent:!0,dependsOn:["build"]},lint:{},"lint:fix":{cache:!1},"ci:check":{},"type-check":{dependsOn:["^build"]},"check:deprecated":{dependsOn:["^build"]},test:{dependsOn:["^build"],outputs:["coverage/**"]},"test:e2e":{dependsOn:["build"],cache:!1}}},null,2)}
712
+ `,Cs=e=>`${JSON.stringify({$schema:`https://biomejs.dev/schemas/${e.replace(/^[\^~]/,"")}/schema.json`,vcs:{enabled:!0,clientKind:"git",useIgnoreFile:!0},files:{includes:["*.json","*.mjs","*.ts",".github/**","!apps","!packages"]},formatter:{enabled:!0,indentStyle:"space",indentWidth:2,lineWidth:100,lineEnding:"lf"},javascript:{formatter:{quoteStyle:"single",semicolons:"always",trailingCommas:"all"}},json:{formatter:{trailingCommas:"none"}},linter:{enabled:!0,rules:{preset:"recommended"}}},null,2)}
713
+ `,Os=()=>`# dependencies
705
714
  node_modules
706
715
  .pnpm-store
707
716
 
@@ -727,7 +736,7 @@ next-env.d.ts
727
736
  *.pem
728
737
  npm-debug.log*
729
738
  .pnpm-debug.log*
730
- `,bs=(e,t)=>`# ${e.name}
739
+ `,As=(e,t)=>`# ${e.name}
731
740
 
732
741
  ${e.description}
733
742
 
@@ -796,7 +805,7 @@ Ranges shared by every app live in the \`catalog:\` section of \`pnpm-workspace.
796
805
  ## Maintenance
797
806
 
798
807
  \`cd apps/<app> && npx @teispace/next-maker doctor --compile\` checks an app against the starter; \`setup --set <option>=<value>\` changes its features.
799
- `,vs=()=>`name: CI
808
+ `,Is=()=>`name: CI
800
809
 
801
810
  on:
802
811
  push:
@@ -838,12 +847,12 @@ jobs:
838
847
  - run: pnpm check:deprecated
839
848
  - run: pnpm test
840
849
  - run: pnpm build
841
- `,$s=()=>`const config = {
850
+ `,Ns=()=>`const config = {
842
851
  '*': ['biome check --write --no-errors-on-unmatched --files-ignore-unknown=true'],
843
852
  };
844
853
 
845
854
  export default config;
846
- `,Ps=()=>`const config = {
855
+ `,Fs=()=>`const config = {
847
856
  extends: ['@commitlint/config-conventional'],
848
857
  rules: {
849
858
  'header-max-length': [2, 'always', 150],
@@ -852,13 +861,13 @@ export default config;
852
861
  };
853
862
 
854
863
  export default config;
855
- `,ks=()=>({"pre-commit":`#!/usr/bin/env sh
864
+ `,Ms=()=>({"pre-commit":`#!/usr/bin/env sh
856
865
  pnpm lint-staged
857
866
  `,"commit-msg":`#!/usr/bin/env sh
858
867
  pnpm exec commitlint --edit "$1"
859
868
  `,"pre-push":`#!/usr/bin/env sh
860
869
  pnpm ci:check && pnpm type-check && pnpm check:deprecated && pnpm test
861
- `}),Ss=(e,t="24")=>`# syntax=docker.io/docker/dockerfile:1
870
+ `}),_s=(e,t="24")=>`# syntax=docker.io/docker/dockerfile:1
862
871
  # Build from the workspace root:
863
872
  # docker build -f apps/${e}/Dockerfile -t ${e} .
864
873
 
@@ -911,7 +920,7 @@ EXPOSE 3000
911
920
  HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \\
912
921
  CMD wget -qO- http://127.0.0.1:3000/robots.txt >/dev/null || exit 1
913
922
  CMD ["node", "apps/${e}/server.js"]
914
- `,Es=e=>`services:
923
+ `,Ds=e=>`services:
915
924
  ${e.map((r,n)=>` ${r}:
916
925
  build:
917
926
  context: .
@@ -928,7 +937,7 @@ ${e.map((r,n)=>` ${r}:
928
937
  API_INTERNAL_URL: \${API_INTERNAL_URL}`).join(`
929
938
 
930
939
  `)}
931
- `,Rs=()=>`node_modules
940
+ `,Ls=()=>`node_modules
932
941
  **/node_modules
933
942
  .git
934
943
  .turbo
@@ -938,12 +947,12 @@ ${e.map((r,n)=>` ${r}:
938
947
  **/test-results
939
948
  **/.env
940
949
  **/.env.*
941
- `,js=e=>{if(e.length===0)return{};let t=o=>({...o.dependencies??{},...o.devDependencies??{}}),r=t(e[0]),n={};for(let[o,s]of Object.entries(r))e.every(i=>t(i)[o]===s)&&(n[o]=s);return Object.fromEntries(Object.entries(n).sort(([o],[s])=>o.localeCompare(s)))},Cs=(e,t)=>{let r=structuredClone(e);for(let n of["dependencies","devDependencies"]){let o=r[n];if(o)for(let s of Object.keys(o))t[s]===o[s]&&(o[s]="catalog:")}return r},Ts=e=>Object.keys(e).length?`
950
+ `,Us=e=>{if(e.length===0)return{};let t=o=>({...o.dependencies??{},...o.devDependencies??{}}),r=t(e[0]),n={};for(let[o,s]of Object.entries(r))e.every(i=>t(i)[o]===s)&&(n[o]=s);return Object.fromEntries(Object.entries(n).sort(([o],[s])=>o.localeCompare(s)))},Gs=(e,t)=>{let r=structuredClone(e);for(let n of["dependencies","devDependencies"]){let o=r[n];if(o)for(let s of Object.keys(o))t[s]===o[s]&&(o[s]="catalog:")}return r},Bs=e=>Object.keys(e).length?`
942
951
  catalog:
943
952
  ${Object.entries(e).map(([t,r])=>` '${t}': '${r}'`).join(`
944
953
  `)}
945
- `:"";var cp=(e,t=[])=>[...t,e],Os={hooks:!1,commitizen:!1,ci:!1,docker:!1,githubTemplates:!1,communityFiles:[]},As=e=>{e.command("workspace <name>").alias("monorepo").description("Create a pnpm + Turborepo workspace with one starter app per --apps entry").option("--apps <names>","Comma-separated app names","web,admin").option("-y, --yes","Skip prompts and use the starter defaults for every app").option("--preset <name>",`Preset for the apps (${Ie().join(", ")})`).option("--set <key=value>","Starter option applied to every app (repeatable)",cp).option("--starter-path <dir>","Compose from a local starter checkout").option("--docker","Per-app Dockerfiles (turbo prune) and a root docker-compose.yml").option("--no-catalog","Keep dependency ranges in each app instead of the pnpm catalog").option("--no-install","Skip dependency installation").option("--no-git","Skip git init").option("--no-ci","Skip the root GitHub Actions workflow").option("--no-hooks","Skip root git hooks (Husky, lint-staged, commitlint)").action(async(t,r)=>{try{await lp(t,r)}catch(n){x(`${n instanceof Error?n.message:n}`),process.exit(1)}})},je=async(e,t,r,n)=>{let o=$t(e);n.current=o;try{let s=await r();return o.succeed(t),s}finally{n.current===o&&(n.current=null)}},pp=e=>{let t=e.split(",").map(r=>r.trim()).filter(Boolean);if(t.length===0)throw new Error("Pass at least one app name with --apps.");for(let r of t)et(r);if(new Set(t).size!==t.length)throw new Error("App names must be unique.");return t},lp=async(e,t)=>{vt(),et(e);let r=pp(t.apps??"web,admin"),n=v.resolve(process.cwd(),e);if(y(n))throw new Error(`Directory ${e} already exists.`);let o={...t.preset?Ne(t.preset):{},...ye(t.set)};for(let[p,m]of Object.entries(Os))o[p]!==void 0&&JSON.stringify(o[p])!==JSON.stringify(m)&&l(fe.yellow(` ! ${p} is managed at the workspace root; ignoring --set ${p}`)),o[p]=m;o.packageManager="pnpm";let s={current:null},i=async()=>{y(n)&&(s.current?.stop(),s.current=null,l(fe.yellow(`
946
- Cleaning up ${e}...`)),await Ze(n))},a=xt(async()=>{l(fe.red(`
947
- Process interrupted.`)),await i()});try{await qt(v.join(n,"apps"),{recursive:!0}),await qt(v.join(n,"packages"),{recursive:!0});let p=B({starterPath:t.starterPath}),m=v.join(n,"apps",r[0]),c=await je(`Fetching starter (${p.location})...`,"Starter fetched.",()=>xe({projectPath:m,source:p,supplied:o,packageManager:"pnpm"}),s);if(!t.yes){let b=await Rt(c.manifest,c.answers);c=tt(c.manifest,{...b,...Os,packageManager:"pnpm"},"pnpm"),l("")}for(let b of c.forced)l(fe.yellow(` ! ${b.reason}; ${b.option} turned off`));let d=JSON.parse(await Jt(v.join(m,"package.json"),"utf-8")),u=await Jt(v.join(m,"pnpm-workspace.yaml"),"utf-8"),f={};for(let b of[".nvmrc",".npmrc",".editorconfig"])y(v.join(m,b))&&(f[b]=await Jt(v.join(m,b),"utf-8"));let h=b=>le(b,{projectName:b,description:`${b} app of ${e}`,readme:!0,copyEnv:!0});await je(`Composing apps/${r[0]}...`,`apps/${r[0]} composed.`,()=>be(m,h(r[0]),c,p),s);for(let b of r.slice(1)){let S=v.join(n,"apps",b);await je(`Composing apps/${b}...`,`apps/${b} composed.`,async()=>{let R=await xe({projectPath:S,source:p,supplied:c.answers,packageManager:"pnpm"});await be(S,h(b),R,p)},s)}let w=[];for(let b of r){let S=v.join(n,"apps",b);for(let D of["pnpm-workspace.yaml","pnpm-lock.yaml",".npmrc",".nvmrc"])await ap(v.join(S,D),{force:!0});let R=JSON.parse(await Jt(v.join(S,"package.json"),"utf-8"));delete R.packageManager,delete R.engines,w.push(R)}let P=t.catalog===!1?{}:js(w);for(let[b,S]of r.entries()){let R=Cs(w[b],P);await I(v.join(n,"apps",S,"package.json"),`${JSON.stringify(R,null,2)}
948
- `),t.docker&&await I(v.join(n,"apps",S,"Dockerfile"),Ss(S))}await je("Writing workspace root...","Workspace root written.",async()=>{let b={name:e,description:`${e} workspace`,author:d.author??"",apps:r,packageManager:"pnpm",packageManagerPin:d.packageManager??"pnpm@11.25.0",nodeEngine:d.engines?.node??">=24.0.0",turboVersion:"^2.10.0",biomeVersion:d.devDependencies?.["@biomejs/biome"]??"^2.5.0",hooks:t.hooks!==!1,huskyVersion:d.devDependencies?.husky,lintStagedVersion:d.devDependencies?.["lint-staged"],commitlintCliVersion:d.devDependencies?.["@commitlint/cli"],commitlintConfigVersion:d.devDependencies?.["@commitlint/config-conventional"]};await I(v.join(n,"package.json"),gs(b)),await I(v.join(n,"pnpm-workspace.yaml"),hs(u)+Ts(P)),await I(v.join(n,"turbo.json"),ys()),await I(v.join(n,"biome.json"),ws(b.biomeVersion)),await I(v.join(n,".gitignore"),xs()),await I(v.join(n,"README.md"),bs(b,c.manifest.starter.version)),await I(v.join(n,"packages",".gitkeep"),"");for(let[S,R]of Object.entries(f))await I(v.join(n,S),R);if(t.docker&&(await I(v.join(n,"docker-compose.yml"),Es(r)),await I(v.join(n,".dockerignore"),Rs())),t.ci!==!1&&(await qt(v.join(n,".github","workflows"),{recursive:!0}),await I(v.join(n,".github","workflows","ci.yml"),vs())),t.hooks!==!1){await I(v.join(n,".lintstagedrc.mjs"),$s()),await I(v.join(n,"commitlint.config.mjs"),Ps()),await qt(v.join(n,".husky"),{recursive:!0});for(let[S,R]of Object.entries(ks())){let D=v.join(n,".husky",S);await I(D,R),await sp(D,493)}}await I(v.join(n,".next-maker.json"),`${JSON.stringify({workspace:!0,apps:r,starter:c.manifest.starter,answers:c.answers,docker:!!t.docker,catalog:t.catalog!==!1},null,2)}
949
- `)},s),t.install!==!1&&(await je("Installing dependencies with pnpm...","Dependencies installed.",()=>pe(n,"pnpm"),s),await je("Formatting...","Formatted.",()=>Et(n,"pnpm","lint:fix"),s));for(let b of r){let S=v.join(n,"apps",b,".env.example");y(S)&&await ip(S,v.join(n,"apps",b,".env"))}t.git!==!1&&await je("Initializing git...","Git initialized.",()=>St(n),s),a(),l(""),l(fe.green(`\u2728 Workspace ${e} is ready with ${r.map(b=>`apps/${b}`).join(", ")}.`)),l(""),l("Next:"),l(fe.cyan(` cd ${e}`)),t.install===!1&&l(fe.cyan(" pnpm install")),l(fe.cyan(` pnpm --filter ${r[0]} dev`)),l("")}catch(p){throw a(),s.current?.fail("Failed to create workspace."),s.current=null,await i(),p}};var Is=e=>{Tn(e),As(e),ms(e),Qo(e),ls(e),zo(e),us(e),ns(e),es(e),Ko(e),Po(e),Yo(e),Ho(e),ts(e),Eo(e),Vo(e),ko(e),rs(e),fs(e)};var dp=process.emitWarning;process.emitWarning=function(e,t,r,n){if(!(typeof e=="string"&&e.includes("--localstorage-file")&&e.includes("was provided without a valid path")))return dp.apply(process,arguments)};async function up(){an({logger:t=>bt(t)});let e=new mp;e.name("next-maker").description("Teispace Next.js Project Generator").version(Te.version),Is(e),e.parse()}up().catch(e=>{let t=e&&typeof e=="object"&&"message"in e?e.message:String(e);bt(`Unexpected error: ${t}`)});
954
+ `:"";var Cp=(e,t=[])=>[...t,e],Vs={hooks:!1,commitizen:!1,ci:!1,docker:!1,githubTemplates:!1,communityFiles:[]},Hs=e=>{e.command("workspace <name>").alias("monorepo").description("Create a pnpm + Turborepo workspace with one starter app per --apps entry").option("--apps <names>","Comma-separated app names","web,admin").option("-y, --yes","Skip prompts and use the starter defaults for every app").option("--preset <name>",`Preset for the apps (${Fe().join(", ")})`).option("--set <key=value>","Starter option applied to every app (repeatable)",Cp).option("--starter-path <dir>","Compose from a local starter checkout").option("--docker","Per-app Dockerfiles (turbo prune) and a root docker-compose.yml").option("--no-catalog","Keep dependency ranges in each app instead of the pnpm catalog").option("--no-install","Skip dependency installation").option("--no-git","Skip git init").option("--no-ci","Skip the root GitHub Actions workflow").option("--no-hooks","Skip root git hooks (Husky, lint-staged, commitlint)").action(async(t,r)=>{try{await Ap(t,r)}catch(n){b(`${n instanceof Error?n.message:n}`),process.exit(1)}})},Ce=async(e,t,r,n)=>{let o=St(e);n.current=o;try{let s=await r();return o.succeed(t),s}finally{n.current===o&&(n.current=null)}},Op=e=>{let t=e.split(",").map(r=>r.trim()).filter(Boolean);if(t.length===0)throw new Error("Pass at least one app name with --apps.");for(let r of t)rt(r);if(new Set(t).size!==t.length)throw new Error("App names must be unique.");return t},Ap=async(e,t)=>{Pt(),rt(e);let r=Op(t.apps??"web,admin"),n=v.resolve(process.cwd(),e);if(w(n))throw new Error(`Directory ${e} already exists.`);let o={...t.preset?Me(t.preset):{},...xe(t.set)};for(let[c,l]of Object.entries(Vs))o[c]!==void 0&&JSON.stringify(o[c])!==JSON.stringify(l)&&m(he.yellow(` ! ${c} is managed at the workspace root; ignoring --set ${c}`)),o[c]=l;o.packageManager="pnpm";let s={current:null},i=async()=>{w(n)&&(s.current?.stop(),s.current=null,m(he.yellow(`
955
+ Cleaning up ${e}...`)),await tt(n))},a=$t(async()=>{m(he.red(`
956
+ Process interrupted.`)),await i()});try{await Wt(v.join(n,"apps"),{recursive:!0}),await Wt(v.join(n,"packages"),{recursive:!0});let c=V({starterPath:t.starterPath}),l=v.join(n,"apps",r[0]),p=await Ce(`Fetching starter (${c.location})...`,"Starter fetched.",()=>ve({projectPath:l,source:c,supplied:o,packageManager:"pnpm"}),s);if(!t.yes){let x=await Ct(p.manifest,p.answers);p=nt(p.manifest,{...x,...Vs,packageManager:"pnpm"},"pnpm"),m("")}for(let x of p.forced)m(he.yellow(` ! ${x.reason}; ${x.option} turned off`));let u=JSON.parse(await Kt(v.join(l,"package.json"),"utf-8")),f=await Kt(v.join(l,"pnpm-workspace.yaml"),"utf-8"),d={};for(let x of[".nvmrc",".npmrc",".editorconfig"])w(v.join(l,x))&&(d[x]=await Kt(v.join(l,x),"utf-8"));let g=x=>me(x,{projectName:x,description:`${x} app of ${e}`,readme:!0,copyEnv:!0});await Ce(`Composing apps/${r[0]}...`,`apps/${r[0]} composed.`,()=>$e(l,g(r[0]),p,c),s);for(let x of r.slice(1)){let E=v.join(n,"apps",x);await Ce(`Composing apps/${x}...`,`apps/${x} composed.`,async()=>{let R=await ve({projectPath:E,source:c,supplied:p.answers,packageManager:"pnpm"});await $e(E,g(x),R,c)},s)}let y=[];for(let x of r){let E=v.join(n,"apps",x);for(let U of["pnpm-workspace.yaml","pnpm-lock.yaml",".npmrc",".nvmrc"])await jp(v.join(E,U),{force:!0});let R=JSON.parse(await Kt(v.join(E,"package.json"),"utf-8"));delete R.packageManager,delete R.engines,y.push(R)}let S=t.catalog===!1?{}:Us(y);for(let[x,E]of r.entries()){let R=Gs(y[x],S);await N(v.join(n,"apps",E,"package.json"),`${JSON.stringify(R,null,2)}
957
+ `),t.docker&&await N(v.join(n,"apps",E,"Dockerfile"),_s(E))}await Ce("Writing workspace root...","Workspace root written.",async()=>{let x={name:e,description:`${e} workspace`,author:u.author??"",apps:r,packageManager:"pnpm",packageManagerPin:u.packageManager??"pnpm@11.25.0",nodeEngine:u.engines?.node??">=24.0.0",turboVersion:"^2.10.0",biomeVersion:u.devDependencies?.["@biomejs/biome"]??"^2.5.0",hooks:t.hooks!==!1,huskyVersion:u.devDependencies?.husky,lintStagedVersion:u.devDependencies?.["lint-staged"],commitlintCliVersion:u.devDependencies?.["@commitlint/cli"],commitlintConfigVersion:u.devDependencies?.["@commitlint/config-conventional"]};await N(v.join(n,"package.json"),Ts(x)),await N(v.join(n,"pnpm-workspace.yaml"),Rs(f)+Bs(S)),await N(v.join(n,"turbo.json"),js()),await N(v.join(n,"biome.json"),Cs(x.biomeVersion)),await N(v.join(n,".gitignore"),Os()),await N(v.join(n,"README.md"),As(x,p.manifest.starter.version)),await N(v.join(n,"packages",".gitkeep"),"");for(let[E,R]of Object.entries(d))await N(v.join(n,E),R);if(t.docker&&(await N(v.join(n,"docker-compose.yml"),Ds(r)),await N(v.join(n,".dockerignore"),Ls())),t.ci!==!1&&(await Wt(v.join(n,".github","workflows"),{recursive:!0}),await N(v.join(n,".github","workflows","ci.yml"),Is())),t.hooks!==!1){await N(v.join(n,".lintstagedrc.mjs"),Ns()),await N(v.join(n,"commitlint.config.mjs"),Fs()),await Wt(v.join(n,".husky"),{recursive:!0});for(let[E,R]of Object.entries(Ms())){let U=v.join(n,".husky",E);await N(U,R),await Tp(U,493)}}await N(v.join(n,".next-maker.json"),`${JSON.stringify({workspace:!0,apps:r,starter:p.manifest.starter,answers:p.answers,docker:!!t.docker,catalog:t.catalog!==!1},null,2)}
958
+ `)},s),t.install!==!1&&(await Ce("Installing dependencies with pnpm...","Dependencies installed.",()=>le(n,"pnpm"),s),await Ce("Formatting...","Formatted.",()=>jt(n,"pnpm","lint:fix"),s));for(let x of r){let E=v.join(n,"apps",x,".env.example");w(E)&&await Rp(E,v.join(n,"apps",x,".env"))}t.git!==!1&&await Ce("Initializing git...","Git initialized.",()=>Rt(n),s),a(),m(""),m(he.green(`\u2728 Workspace ${e} is ready with ${r.map(x=>`apps/${x}`).join(", ")}.`)),m(""),m("Next:"),m(he.cyan(` cd ${e}`)),t.install===!1&&m(he.cyan(" pnpm install")),m(he.cyan(` pnpm --filter ${r[0]} dev`)),m("")}catch(c){throw a(),s.current?.fail("Failed to create workspace."),s.current=null,await i(),c}};var qs=e=>{Dn(e),Hs(e),ks(e),is(e),$s(e),es(e),Ss(e),ms(e),cs(e),ns(e),Oo(e),ss(e),rs(e),ps(e),No(e),Yo(e),Ao(e),ls(e),Es(e)};var Np=process.emitWarning;process.emitWarning=function(e,t,r,n){if(!(typeof e=="string"&&e.includes("--localstorage-file")&&e.includes("was provided without a valid path")))return Np.apply(process,arguments)};async function Fp(){gn({logger:t=>kt(t)});let e=new Ip;e.name("next-maker").description("Teispace Next.js Project Generator").version(Ae.version),qs(e),e.parse()}Fp().catch(e=>{let t=e&&typeof e=="object"&&"message"in e?e.message:String(e);kt(`Unexpected error: ${t}`)});